Chute Implementation

- Chutes can now transfer items
- Chutes now propagate air flow from attached fans
- Fixed a few issues with mechanical arms
- Removed unused chute models
- Implemented appropriate interactions between funnels and chutes
This commit is contained in:
simibubi 2020-07-02 17:23:42 +02:00
parent f820e2be27
commit cd189a5fa9
27 changed files with 891 additions and 368 deletions

View file

@ -74,8 +74,8 @@ public class AllShapes {
.add(0, 10, 0, 16, 13, 16) .add(0, 10, 0, 16, 13, 16)
.forDirectional(UP), .forDirectional(UP),
CHUTE_FUNNEL = shape(3, -2, 3, 13, 2, 13).add(2, 2, 2, 14, 6, 14) CHUTE_FUNNEL = shape(3, -2, 3, 13, 2, 13).add(2, 2, 2, 14, 6, 14)
.add(1, 5, 1, 15, 16, 15)
.add(0, 8, 0, 16, 14, 16) .add(0, 8, 0, 16, 14, 16)
.add(1, 5, 1, 15, 18, 15)
.forDirectional(UP), .forDirectional(UP),
BELT_FUNNEL_RETRACTED = shape(3, -5, 14, 13, 13, 19).add(0, -5, 8, 16, 16, 14) BELT_FUNNEL_RETRACTED = shape(3, -5, 14, 13, 13, 19).add(0, -5, 8, 16, 16, 14)
.forHorizontal(NORTH), .forHorizontal(NORTH),

View file

@ -72,6 +72,8 @@ import com.simibubi.create.content.logistics.block.belts.observer.BeltObserverRe
import com.simibubi.create.content.logistics.block.belts.observer.BeltObserverTileEntity; import com.simibubi.create.content.logistics.block.belts.observer.BeltObserverTileEntity;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity;
import com.simibubi.create.content.logistics.block.chute.ChuteRenderer;
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
import com.simibubi.create.content.logistics.block.depot.DepotRenderer; import com.simibubi.create.content.logistics.block.depot.DepotRenderer;
import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; import com.simibubi.create.content.logistics.block.depot.DepotTileEntity;
import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity;
@ -154,6 +156,8 @@ public class AllTileEntities {
register("fluid_tank", FluidTankTileEntity::new, AllBlocks.FLUID_TANK); register("fluid_tank", FluidTankTileEntity::new, AllBlocks.FLUID_TANK);
public static final TileEntityEntry<BeltTileEntity> BELT = register("belt", BeltTileEntity::new, AllBlocks.BELT); public static final TileEntityEntry<BeltTileEntity> BELT = register("belt", BeltTileEntity::new, AllBlocks.BELT);
public static final TileEntityEntry<ChuteTileEntity> CHUTE =
register("chute", ChuteTileEntity::new, AllBlocks.CHUTE);
public static final TileEntityEntry<BeltTunnelTileEntity> BELT_TUNNEL = public static final TileEntityEntry<BeltTunnelTileEntity> BELT_TUNNEL =
register("belt_tunnel", BeltTunnelTileEntity::new, AllBlocks.BELT_TUNNEL); register("belt_tunnel", BeltTunnelTileEntity::new, AllBlocks.BELT_TUNNEL);
public static final TileEntityEntry<ArmTileEntity> MECHANICAL_ARM = public static final TileEntityEntry<ArmTileEntity> MECHANICAL_ARM =
@ -301,6 +305,7 @@ public class AllTileEntities {
bind(ROTATION_SPEED_CONTROLLER, SpeedControllerRenderer::new); bind(ROTATION_SPEED_CONTROLLER, SpeedControllerRenderer::new);
bind(PACKAGER, PackagerRenderer::new); bind(PACKAGER, PackagerRenderer::new);
bind(DEPOT, DepotRenderer::new); bind(DEPOT, DepotRenderer::new);
bind(CHUTE, ChuteRenderer::new);
bind(CREATIVE_CRATE, SmartTileEntityRenderer::new); bind(CREATIVE_CRATE, SmartTileEntityRenderer::new);
bind(REDSTONE_LINK, SmartTileEntityRenderer::new); bind(REDSTONE_LINK, SmartTileEntityRenderer::new);

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.components.fan; package com.simibubi.create.content.contraptions.components.fan;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
@ -34,6 +35,14 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements ITE<Enca
blockUpdate(state, worldIn, pos); blockUpdate(state, worldIn, pos);
} }
@Override
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState p_196243_4_, boolean p_196243_5_) {
if (state.hasTileEntity() && (state.getBlock() != p_196243_4_.getBlock() || !p_196243_4_.hasTileEntity())) {
withTileEntityDo(world, pos, EncasedFanTileEntity::updateChute);
world.removeTileEntity(pos);
}
}
@Override @Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) { boolean isMoving) {
@ -42,11 +51,22 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements ITE<Enca
@Override @Override
public BlockState getStateForPlacement(BlockItemUseContext context) { public BlockState getStateForPlacement(BlockItemUseContext context) {
World world = context.getWorld();
BlockPos pos = context.getPos();
Direction face = context.getFace();
BlockState placedOn = world.getBlockState(pos.offset(face.getOpposite()));
BlockState placedOnOpposite = world.getBlockState(pos.offset(face));
if (AllBlocks.CHUTE.has(placedOn))
return getDefaultState().with(FACING, face.getOpposite());
if (AllBlocks.CHUTE.has(placedOnOpposite))
return getDefaultState().with(FACING, face);
Direction preferredFacing = getPreferredFacing(context); Direction preferredFacing = getPreferredFacing(context);
if (preferredFacing == null) if (preferredFacing == null)
preferredFacing = context.getNearestLookingDirection(); preferredFacing = context.getNearestLookingDirection();
return getDefaultState().with(FACING, return getDefaultState().with(FACING, context.getPlayer()
context.getPlayer().isSneaking() ? preferredFacing : preferredFacing.getOpposite()); .isSneaking() ? preferredFacing : preferredFacing.getOpposite());
} }
protected void blockUpdate(BlockState state, World worldIn, BlockPos pos) { protected void blockUpdate(BlockState state, World worldIn, BlockPos pos) {
@ -70,12 +90,14 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements ITE<Enca
@Override @Override
public Axis getRotationAxis(BlockState state) { public Axis getRotationAxis(BlockState state) {
return state.get(FACING).getAxis(); return state.get(FACING)
.getAxis();
} }
@Override @Override
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) { public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) {
return face == state.get(FACING).getOpposite(); return face == state.get(FACING)
.getOpposite();
} }
@Override @Override

View file

@ -2,11 +2,13 @@ package com.simibubi.create.content.contraptions.components.fan;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity;
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.CKinetics; import com.simibubi.create.foundation.config.CKinetics;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -60,7 +62,8 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
} }
public void updateGenerator(Direction facing) { public void updateGenerator(Direction facing) {
boolean shouldGenerate = world.isBlockPowered(pos) && facing == Direction.DOWN && world.isBlockPresent(pos.down()) && blockBelowIsHot(); boolean shouldGenerate = world.isBlockPowered(pos) && facing == Direction.DOWN
&& world.isBlockPresent(pos.down()) && blockBelowIsHot();
if (shouldGenerate == isGenerator) if (shouldGenerate == isGenerator)
return; return;
@ -69,7 +72,9 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
} }
public boolean blockBelowIsHot() { public boolean blockBelowIsHot() {
return world.getBlockState(pos.down()).getBlock().isIn(AllBlockTags.FAN_HEATERS.tag); return world.getBlockState(pos.down())
.getBlock()
.isIn(AllBlockTags.FAN_HEATERS.tag);
} }
public float getMaxDistance() { public float getMaxDistance() {
@ -94,6 +99,22 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
public void onSpeedChanged(float prevSpeed) { public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed); super.onSpeedChanged(prevSpeed);
updateAirFlow = true; updateAirFlow = true;
updateChute();
}
public void updateChute() {
Direction direction = getBlockState().get(EncasedFanBlock.FACING);
if (!direction.getAxis()
.isVertical())
return;
TileEntity poweredChute = world.getTileEntity(pos.offset(direction));
if (!(poweredChute instanceof ChuteTileEntity))
return;
ChuteTileEntity chuteTE = (ChuteTileEntity) poweredChute;
if (direction == Direction.DOWN)
chuteTE.updatePull();
else
chuteTE.updatePush(1);
} }
public void blockInFrontChanged() { public void blockInFrontChanged() {

View file

@ -9,6 +9,9 @@ import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
public class TransportedItemStack implements Comparable<TransportedItemStack> { public class TransportedItemStack implements Comparable<TransportedItemStack> {
private static Random R = new Random();
public ItemStack stack; public ItemStack stack;
public float beltPosition; public float beltPosition;
public float sideOffset; public float sideOffset;
@ -25,7 +28,7 @@ public class TransportedItemStack implements Comparable<TransportedItemStack> {
public TransportedItemStack(ItemStack stack) { public TransportedItemStack(ItemStack stack) {
this.stack = stack; this.stack = stack;
angle = new Random().nextInt(360); angle = R.nextInt(360);
sideOffset = prevSideOffset = getTargetSideOffset(); sideOffset = prevSideOffset = getTargetSideOffset();
insertedFrom = Direction.UP; insertedFrom = Direction.UP;
} }

View file

@ -4,23 +4,34 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
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.ItemUseContext; import net.minecraft.item.ItemUseContext;
import net.minecraft.state.DirectionProperty; import net.minecraft.state.DirectionProperty;
import net.minecraft.state.EnumProperty; import net.minecraft.state.EnumProperty;
import net.minecraft.state.IProperty; import net.minecraft.state.IProperty;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType; import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.IStringSerializable; import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
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.world.IBlockReader; import net.minecraft.world.IBlockReader;
@ -28,7 +39,7 @@ 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 ChuteBlock extends Block implements IWrenchable { public class ChuteBlock extends Block implements IWrenchable, ITE<ChuteTileEntity> {
public static final IProperty<Shape> SHAPE = EnumProperty.create("shape", Shape.class); public static final IProperty<Shape> SHAPE = EnumProperty.create("shape", Shape.class);
public static final DirectionProperty FACING = BlockStateProperties.FACING_EXCEPT_UP; public static final DirectionProperty FACING = BlockStateProperties.FACING_EXCEPT_UP;
@ -41,6 +52,16 @@ public class ChuteBlock extends Block implements IWrenchable {
} }
} }
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.CHUTE.create();
}
public ChuteBlock(Properties p_i48440_1_) { public ChuteBlock(Properties p_i48440_1_) {
super(p_i48440_1_); super(p_i48440_1_);
setDefaultState(getDefaultState().with(SHAPE, Shape.NORMAL) setDefaultState(getDefaultState().with(SHAPE, Shape.NORMAL)
@ -48,10 +69,34 @@ public class ChuteBlock extends Block implements IWrenchable {
} }
@Override @Override
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { public void onLanded(IBlockReader worldIn, Entity entityIn) {
if (p_220082_5_) super.onLanded(worldIn, entityIn);
if (!(entityIn instanceof ItemEntity))
return;
if (entityIn.world.isRemote)
return;
DirectBeltInputBehaviour input = TileEntityBehaviour.get(entityIn.world, new BlockPos(entityIn.getPositionVec()
.add(0, 0.5f, 0)).down(), DirectBeltInputBehaviour.TYPE);
if (input == null)
return;
if (!input.canInsertFromSide(Direction.UP))
return; return;
ItemEntity itemEntity = (ItemEntity) entityIn;
ItemStack toInsert = itemEntity.getItem();
ItemStack remainder = input.handleInsertion(toInsert, Direction.UP, false);
if (remainder.isEmpty())
itemEntity.remove();
if (remainder.getCount() < toInsert.getCount())
itemEntity.setItem(remainder);
}
@Override
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) {
withTileEntityDo(world, pos, ChuteTileEntity::onAdded);
if (p_220082_5_)
return;
updateDiagonalNeighbour(state, world, pos); updateDiagonalNeighbour(state, world, pos);
} }
@ -72,6 +117,7 @@ public class ChuteBlock extends Block implements IWrenchable {
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState p_196243_4_, boolean p_196243_5_) { public void onReplaced(BlockState state, World world, BlockPos pos, BlockState p_196243_4_, boolean p_196243_5_) {
boolean differentBlock = state.getBlock() != p_196243_4_.getBlock(); boolean differentBlock = state.getBlock() != p_196243_4_.getBlock();
if (state.hasTileEntity() && (differentBlock || !p_196243_4_.hasTileEntity())) { if (state.hasTileEntity() && (differentBlock || !p_196243_4_.hasTileEntity())) {
withTileEntityDo(world, pos, c -> c.onRemoved(state));
world.removeTileEntity(pos); world.removeTileEntity(pos);
} }
if (p_196243_5_ || !differentBlock) if (p_196243_5_ || !differentBlock)
@ -175,4 +221,33 @@ public class ChuteBlock extends Block implements IWrenchable {
super.fillStateContainer(p_206840_1_.add(SHAPE, FACING)); super.fillStateContainer(p_206840_1_.add(SHAPE, FACING));
} }
@Override
public Class<ChuteTileEntity> getTileEntityClass() {
return ChuteTileEntity.class;
}
@Override
public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player, Hand hand,
BlockRayTraceResult p_225533_6_) {
if (!player.getHeldItem(hand)
.isEmpty())
return ActionResultType.PASS;
if (world.isRemote)
return ActionResultType.SUCCESS;
try {
ChuteTileEntity te = getTileEntity(world, pos);
if (te == null)
return ActionResultType.PASS;
if (te.item.isEmpty())
return ActionResultType.PASS;
player.inventory.placeItemBackInInventory(world, te.item);
te.setItem(ItemStack.EMPTY);
return ActionResultType.SUCCESS;
} catch (TileEntityException e) {
e.printStackTrace();
}
return ActionResultType.PASS;
}
} }

View file

@ -0,0 +1,52 @@
package com.simibubi.create.content.logistics.block.chute;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
public class ChuteItemHandler implements IItemHandler {
private ChuteTileEntity te;
public ChuteItemHandler(ChuteTileEntity te) {
this.te = te;
}
@Override
public int getSlots() {
return 1;
}
@Override
public ItemStack getStackInSlot(int slot) {
return te.item;
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (!te.item.isEmpty())
return stack;
if (!simulate)
te.setItem(stack);
return ItemStack.EMPTY;
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
ItemStack remainder = te.item.copy();
ItemStack split = remainder.split(amount);
if (!simulate)
te.setItem(remainder);
return split;
}
@Override
public int getSlotLimit(int slot) {
return Math.min(64, getStackInSlot(slot).getMaxStackSize());
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
}
}

View file

@ -0,0 +1,48 @@
package com.simibubi.create.content.logistics.block.chute;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.Direction;
public class ChuteRenderer extends SafeTileEntityRenderer<ChuteTileEntity> {
public ChuteRenderer(TileEntityRendererDispatcher dispatcher) {
super(dispatcher);
}
@Override
protected void renderSafe(ChuteTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
if (te.item.isEmpty())
return;
BlockState blockState = te.getBlockState();
if (blockState.get(ChuteBlock.FACING) != Direction.DOWN)
return;
if (blockState.get(ChuteBlock.SHAPE) != Shape.WINDOW_STRAIGHT)
return;
ItemRenderer itemRenderer = Minecraft.getInstance()
.getItemRenderer();
MatrixStacker msr = MatrixStacker.of(ms);
ms.push();
msr.centre();
float itemScale = .5f;
float itemPosition = te.itemPosition.get(partialTicks);
ms.translate(0, -.5 + itemPosition, 0);
ms.scale(itemScale, itemScale, itemScale);
msr.rotateX(itemPosition * 180);
msr.rotateY(itemPosition * 180);
itemRenderer.renderItem(te.item, TransformType.FIXED, light, overlay, ms, buffer);
ms.pop();
}
}

View file

@ -0,0 +1,465 @@
package com.simibubi.create.content.logistics.block.chute;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.fan.EncasedFanBlock;
import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity;
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape;
import com.simibubi.create.content.logistics.block.realityFunnel.ChuteFunnelBlock;
import com.simibubi.create.content.logistics.block.realityFunnel.RealityFunnelBlock;
import com.simibubi.create.foundation.gui.widgets.InterpolatedValue;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInformation {
float pull;
float push;
ItemStack item;
InterpolatedValue itemPosition;
ChuteItemHandler itemHandler;
LazyOptional<IItemHandler> lazyHandler;
boolean canPickUpItems;
public ChuteTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
item = ItemStack.EMPTY;
itemPosition = new InterpolatedValue();
itemHandler = new ChuteItemHandler(this);
lazyHandler = LazyOptional.of(() -> itemHandler);
canPickUpItems = false;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached()));
}
// Cached per-tick, useful when a lot of items are waiting on top of it
public boolean canDirectlyInsertCached() {
return canPickUpItems;
}
private boolean canDirectlyInsert() {
BlockState blockState = getBlockState();
BlockState blockStateAbove = world.getBlockState(pos.up());
if (!AllBlocks.CHUTE.has(blockState))
return false;
if (AllBlocks.CHUTE.has(blockStateAbove) && blockStateAbove.get(ChuteBlock.FACING) == Direction.DOWN)
return false;
if (getItemMotion() > 0 && getInputChutes().isEmpty())
return false;
return blockState.get(ChuteBlock.FACING) == Direction.DOWN || blockState.get(ChuteBlock.SHAPE) == Shape.START;
}
@Override
public void initialize() {
super.initialize();
}
@Override
public void tick() {
super.tick();
canPickUpItems = canDirectlyInsert();
if (item.isEmpty())
return;
float itemMotion = getItemMotion();
float nextOffset = itemPosition.value + itemMotion;
if (itemMotion < 0) {
if (nextOffset < .5f) {
if (handleSideOutput())
return;
boolean success = handleDownwardOutput(true);
if (!success)
nextOffset = .5f;
else if (nextOffset < 0) {
handleDownwardOutput(world.isRemote);
return;
}
}
}
if (itemMotion > 0) {
if (nextOffset > .5f) {
if (handleSideOutput())
return;
boolean success = handleUpwardOutput(true);
if (!success)
nextOffset = .5f;
else if (nextOffset > 1) {
handleUpwardOutput(world.isRemote);
return;
}
}
}
itemPosition.set(nextOffset);
}
private boolean handleDownwardOutput(boolean simulate) {
BlockState blockState = getBlockState();
ChuteTileEntity targetChute = getTargetChute(blockState);
if (targetChute != null) {
boolean canInsert = targetChute.item.isEmpty();
if (!simulate && canInsert) {
targetChute.setItem(item, 1);
setItem(ItemStack.EMPTY);
}
return canInsert;
}
// Diagonal chutes can only insert into other chutes
if (blockState.get(ChuteBlock.FACING)
.getAxis()
.isHorizontal())
return false;
BlockState stateBelow = world.getBlockState(pos.down());
if (AllBlocks.REALITY_FUNNEL.has(stateBelow)) {
if (stateBelow.get(RealityFunnelBlock.POWERED))
return false;
if (stateBelow.get(RealityFunnelBlock.FACING) != Direction.UP)
return false;
ItemStack remainder = RealityFunnelBlock.tryInsert(world, pos.down(), item, simulate);
if (!simulate)
setItem(remainder);
return remainder.isEmpty();
}
DirectBeltInputBehaviour directInput =
TileEntityBehaviour.get(world, pos.down(), DirectBeltInputBehaviour.TYPE);
if (directInput != null) {
if (!directInput.canInsertFromSide(Direction.UP))
return false;
ItemStack remainder = directInput.handleInsertion(item, Direction.UP, simulate);
if (!simulate)
setItem(remainder);
return remainder.isEmpty();
}
if (Block.hasSolidSideOnTop(world, pos.down()))
return false;
if (!simulate) {
Vec3d dropVec = VecHelper.getCenterOf(pos)
.add(0, -12 / 16f, 0);
ItemEntity dropped = new ItemEntity(world, dropVec.x, dropVec.y, dropVec.z, item.copy());
dropped.setDefaultPickupDelay();
dropped.setMotion(0, -.25f, 0);
world.addEntity(dropped);
setItem(ItemStack.EMPTY);
}
return true;
}
private boolean handleUpwardOutput(boolean simulate) {
BlockState stateAbove = world.getBlockState(pos.up());
if (AllBlocks.REALITY_FUNNEL.has(stateAbove)) {
if (!stateAbove.get(RealityFunnelBlock.POWERED)
&& stateAbove.get(RealityFunnelBlock.FACING) == Direction.DOWN) {
ItemStack remainder = RealityFunnelBlock.tryInsert(world, pos.up(), item, simulate);
if (remainder.isEmpty()) {
if (!simulate)
setItem(remainder);
return true;
}
}
}
ChuteTileEntity bestOutput = null;
List<ChuteTileEntity> inputChutes = getInputChutes();
for (ChuteTileEntity targetChute : inputChutes) {
if (!targetChute.item.isEmpty())
continue;
float itemMotion = targetChute.getItemMotion();
if (itemMotion < 0)
continue;
if (bestOutput == null || bestOutput.getItemMotion() < itemMotion) {
bestOutput = targetChute;
}
}
if (bestOutput != null) {
if (!simulate) {
bestOutput.setItem(item, 0);
setItem(ItemStack.EMPTY);
}
return true;
}
if (Block.hasSolidSide(stateAbove, world, pos.up(), Direction.DOWN))
return false;
if (!inputChutes.isEmpty())
return false;
if (!simulate) {
Vec3d dropVec = VecHelper.getCenterOf(pos)
.add(0, 8 / 16f, 0);
ItemEntity dropped = new ItemEntity(world, dropVec.x, dropVec.y, dropVec.z, item.copy());
dropped.setDefaultPickupDelay();
dropped.setMotion(0, getItemMotion() * 2, 0);
world.addEntity(dropped);
setItem(ItemStack.EMPTY);
}
return true;
}
private boolean handleSideOutput() {
if (world.isRemote)
return false;
for (Direction direction : Iterate.horizontalDirections) {
BlockPos funnelPos = pos.offset(direction);
BlockState funnelState = world.getBlockState(funnelPos);
if (AllBlocks.CHUTE_FUNNEL.has(funnelState)) {
if (funnelState.get(ChuteFunnelBlock.POWERED))
continue;
if (funnelState.get(ChuteFunnelBlock.HORIZONTAL_FACING) != direction.getOpposite())
continue;
if (funnelState.get(ChuteFunnelBlock.PUSHING))
continue;
ItemStack remainder = RealityFunnelBlock.tryInsert(world, funnelPos, item.copy(), world.isRemote);
if (remainder.getCount() != item.getCount() && !world.isRemote)
setItem(remainder);
}
}
return item.isEmpty();
}
public void setItem(ItemStack stack) {
setItem(stack, getItemMotion() < 0 ? 1 : 0);
}
public void setItem(ItemStack stack, float insertionPos) {
item = stack;
itemPosition.lastValue = itemPosition.value = insertionPos;
markDirty();
sendData();
}
@Override
public void remove() {
super.remove();
if (lazyHandler != null)
lazyHandler.invalidate();
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.put("Item", item.serializeNBT());
compound.putFloat("ItemPosition", itemPosition.value);
compound.putFloat("Pull", pull);
compound.putFloat("Push", push);
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
ItemStack previousItem = item;
item = ItemStack.read(compound.getCompound("Item"));
itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition");
pull = compound.getFloat("Pull");
push = compound.getFloat("Push");
super.read(compound);
if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) {
if (world.rand.nextInt(3) != 0)
return;
Vec3d p = VecHelper.getCenterOf(pos);
p = VecHelper.offsetRandomly(p, world.rand, .5f);
Vec3d m = Vec3d.ZERO;
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, item), p.x, p.y, p.z, m.x, m.y, m.z);
}
}
public float getItemMotion() {
// Chutes per second
final float fanSpeedModifier = 1 / 64f;
final float maxUpwardItemSpeed = 20f;
final float gravity = 4f;
float upwardMotion = (push + pull) * fanSpeedModifier;
return (upwardMotion == 0 ? -gravity : MathHelper.clamp(upwardMotion, 0, maxUpwardItemSpeed)) / 20f;
}
public void onRemoved(BlockState chuteState) {
ChuteTileEntity targetChute = getTargetChute(chuteState);
List<ChuteTileEntity> inputChutes = getInputChutes();
if (!item.isEmpty())
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), item);
super.remove();
if (targetChute != null) {
targetChute.updatePull();
targetChute.propagatePush();
}
inputChutes.forEach(c -> c.updatePush(inputChutes.size()));
}
public void onAdded() {
updateContainingBlockInfo();
updatePull();
ChuteTileEntity targetChute = getTargetChute(getBlockState());
if (targetChute != null)
targetChute.propagatePush();
else
updatePush(1);
}
public void updatePull() {
float totalPull = calculatePull();
if (pull == totalPull)
return;
pull = totalPull;
sendData();
ChuteTileEntity targetChute = getTargetChute(getBlockState());
if (targetChute != null)
targetChute.updatePull();
}
public void updatePush(int branchCount) {
float totalPush = calculatePush(branchCount);
if (push == totalPush)
return;
push = totalPush;
sendData();
propagatePush();
}
public void propagatePush() {
List<ChuteTileEntity> inputs = getInputChutes();
inputs.forEach(c -> c.updatePush(inputs.size()));
}
protected float calculatePull() {
BlockState blockStateAbove = world.getBlockState(pos.up());
if (AllBlocks.ENCASED_FAN.has(blockStateAbove)
&& blockStateAbove.get(EncasedFanBlock.FACING) == Direction.DOWN) {
TileEntity te = world.getTileEntity(pos.up());
if (te instanceof EncasedFanTileEntity && !te.isRemoved()) {
EncasedFanTileEntity fan = (EncasedFanTileEntity) te;
return Math.abs(fan.getSpeed());
}
}
float totalPull = 0;
for (Direction d : Iterate.directions) {
ChuteTileEntity inputChute = getInputChute(d);
if (inputChute == null)
continue;
totalPull += inputChute.pull;
}
return totalPull;
}
protected float calculatePush(int branchCount) {
BlockState blockStateBelow = world.getBlockState(pos.down());
if (AllBlocks.ENCASED_FAN.has(blockStateBelow) && blockStateBelow.get(EncasedFanBlock.FACING) == Direction.UP) {
TileEntity te = world.getTileEntity(pos.down());
if (te instanceof EncasedFanTileEntity && !te.isRemoved()) {
EncasedFanTileEntity fan = (EncasedFanTileEntity) te;
return Math.abs(fan.getSpeed());
}
}
ChuteTileEntity targetChute = getTargetChute(getBlockState());
if (targetChute == null)
return 0;
return targetChute.push / branchCount;
}
@Nullable
private ChuteTileEntity getTargetChute(BlockState state) {
Direction targetDirection = state.get(ChuteBlock.FACING);
BlockPos chutePos = pos.down();
if (targetDirection.getAxis()
.isHorizontal())
chutePos = chutePos.offset(targetDirection.getOpposite());
BlockState chuteState = world.getBlockState(chutePos);
if (!AllBlocks.CHUTE.has(chuteState))
return null;
TileEntity te = world.getTileEntity(chutePos);
if (te instanceof ChuteTileEntity)
return (ChuteTileEntity) te;
return null;
}
private List<ChuteTileEntity> getInputChutes() {
List<ChuteTileEntity> inputs = new LinkedList<>();
for (Direction d : Iterate.directions) {
ChuteTileEntity inputChute = getInputChute(d);
if (inputChute == null)
continue;
inputs.add(inputChute);
}
return inputs;
}
@Nullable
private ChuteTileEntity getInputChute(Direction direction) {
if (direction == Direction.DOWN)
return null;
direction = direction.getOpposite();
BlockPos chutePos = pos.up();
if (direction.getAxis()
.isHorizontal())
chutePos = chutePos.offset(direction);
BlockState chuteState = world.getBlockState(chutePos);
if (!AllBlocks.CHUTE.has(chuteState) || chuteState.get(ChuteBlock.FACING) != direction)
return null;
TileEntity te = world.getTileEntity(chutePos);
if (te instanceof ChuteTileEntity && !te.isRemoved())
return (ChuteTileEntity) te;
return null;
}
@Override
public boolean addToGoggleTooltip(List<String> tooltip, boolean isPlayerSneaking) {
tooltip.add(spacing + TextFormatting.GOLD + "Pull: " + TextFormatting.WHITE + pull);
tooltip.add(spacing + TextFormatting.GOLD + "Push: " + TextFormatting.WHITE + push);
tooltip.add(TextFormatting.YELLOW + "-> Item Motion: " + TextFormatting.WHITE + getItemMotion());
return true;
}
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return lazyHandler.cast();
return super.getCapability(cap, side);
}
public ItemStack getItem() {
return item;
}
}

View file

@ -64,8 +64,9 @@ public class DepotBlock extends Block implements ITE<DepotTileEntity> {
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
withTileEntityDo(world, pos, te -> { withTileEntityDo(world, pos, te -> {
boolean wasEmptyHanded = player.getHeldItem(hand) ItemStack heldItem = player.getHeldItem(hand);
.isEmpty(); boolean wasEmptyHanded = heldItem.isEmpty();
boolean shouldntPlaceItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem);
ItemStack mainItemStack = te.getHeldItemStack(); ItemStack mainItemStack = te.getHeldItemStack();
if (!mainItemStack.isEmpty()) { if (!mainItemStack.isEmpty()) {
@ -76,12 +77,12 @@ public class DepotBlock extends Block implements ITE<DepotTileEntity> {
for (int i = 0; i < outputs.getSlots(); i++) for (int i = 0; i < outputs.getSlots(); i++)
player.inventory.placeItemBackInInventory(world, outputs.extractItem(i, 64, false)); player.inventory.placeItemBackInInventory(world, outputs.extractItem(i, 64, false));
if (!wasEmptyHanded) { if (!wasEmptyHanded && !shouldntPlaceItem) {
TransportedItemStack heldItem = new TransportedItemStack(player.getHeldItem(hand)); TransportedItemStack transported = new TransportedItemStack(heldItem);
heldItem.insertedFrom = player.getHorizontalFacing(); transported.insertedFrom = player.getHorizontalFacing();
heldItem.prevBeltPosition = .25f; transported.prevBeltPosition = .25f;
heldItem.beltPosition = .25f; transported.beltPosition = .25f;
te.setHeldItem(heldItem); te.setHeldItem(transported);
player.setHeldItem(hand, ItemStack.EMPTY); player.setHeldItem(hand, ItemStack.EMPTY);
} }

View file

@ -3,16 +3,24 @@ package com.simibubi.create.content.logistics.block.mechanicalArm;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticBlock; import com.simibubi.create.content.contraptions.base.KineticBlock;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
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.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> { public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
@ -46,4 +54,34 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
return ArmTileEntity.class; return ArmTileEntity.class;
} }
@Override
public void onReplaced(BlockState p_196243_1_, World world, BlockPos pos, BlockState p_196243_4_,
boolean p_196243_5_) {
if (p_196243_1_.hasTileEntity()
&& (p_196243_1_.getBlock() != p_196243_4_.getBlock() || !p_196243_4_.hasTileEntity())) {
withTileEntityDo(world, pos, te -> {
if (!te.heldItem.isEmpty())
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), te.heldItem);
});
world.removeTileEntity(pos);
}
}
@Override
public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player,
Hand p_225533_5_, BlockRayTraceResult p_225533_6_) {
if (world.isRemote)
return ActionResultType.SUCCESS;
withTileEntityDo(world, pos, te -> {
if (te.heldItem.isEmpty())
return;
player.inventory.placeItemBackInInventory(world, te.heldItem);
te.heldItem = ItemStack.EMPTY;
te.phase = Phase.SEARCH_INPUTS;
te.markDirty();
te.sendData();
});
return ActionResultType.SUCCESS;
}
} }

View file

@ -147,6 +147,8 @@ public abstract class ArmInteractionPoint {
static ArmInteractionPoint deserialize(IBlockReader world, CompoundNBT nbt) { static ArmInteractionPoint deserialize(IBlockReader world, CompoundNBT nbt) {
BlockPos pos = NBTUtil.readBlockPos(nbt.getCompound("Pos")); BlockPos pos = NBTUtil.readBlockPos(nbt.getCompound("Pos"));
ArmInteractionPoint interactionPoint = createAt(world, pos); ArmInteractionPoint interactionPoint = createAt(world, pos);
if (interactionPoint == null)
return null;
interactionPoint.mode = NBTHelper.readEnum(nbt, "Mode", Mode.class); interactionPoint.mode = NBTHelper.readEnum(nbt, "Mode", Mode.class);
return interactionPoint; return interactionPoint;
} }

View file

@ -172,9 +172,11 @@ public class ArmTileEntity extends KineticTileEntity {
protected void depositItem() { protected void depositItem() {
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
if (armInteractionPoint != null) {
ItemStack toInsert = heldItem.copy(); ItemStack toInsert = heldItem.copy();
ItemStack remainder = armInteractionPoint.insert(world, toInsert, false); ItemStack remainder = armInteractionPoint.insert(world, toInsert, false);
heldItem = remainder; heldItem = remainder;
}
phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS; phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS;
chasedPointProgress = 0; chasedPointProgress = 0;
chasedPointIndex = -1; chasedPointIndex = -1;
@ -184,6 +186,7 @@ public class ArmTileEntity extends KineticTileEntity {
protected void collectItem() { protected void collectItem() {
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
if (armInteractionPoint != null)
for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) { for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) {
int amountExtracted = getDistributableAmount(armInteractionPoint, i); int amountExtracted = getDistributableAmount(armInteractionPoint, i);
if (amountExtracted == 0) if (amountExtracted == 0)
@ -221,6 +224,8 @@ public class ArmTileEntity extends KineticTileEntity {
outputs.clear(); outputs.clear();
for (INBT inbt : interactionPointTag) { for (INBT inbt : interactionPointTag) {
ArmInteractionPoint point = ArmInteractionPoint.deserialize(world, (CompoundNBT) inbt); ArmInteractionPoint point = ArmInteractionPoint.deserialize(world, (CompoundNBT) inbt);
if (point == null)
continue;
if (point.mode == Mode.DEPOSIT) if (point.mode == Mode.DEPOSIT)
outputs.add(point); outputs.add(point);
if (point.mode == Mode.TAKE) if (point.mode == Mode.TAKE)

View file

@ -76,21 +76,26 @@ public class RealityFunnelBlock extends ProperDirectionalBlock implements ITE<Re
if (projectedDiff < 0 == (direction.getAxisDirection() == AxisDirection.POSITIVE)) if (projectedDiff < 0 == (direction.getAxisDirection() == AxisDirection.POSITIVE))
return; return;
FilteringBehaviour filter = TileEntityBehaviour.get(worldIn, pos, FilteringBehaviour.TYPE);
InsertingBehaviour inserter = TileEntityBehaviour.get(worldIn, pos, InsertingBehaviour.TYPE);
if (inserter == null)
return;
ItemStack toInsert = itemEntity.getItem(); ItemStack toInsert = itemEntity.getItem();
if (filter != null && !filter.test(toInsert)) ItemStack remainder = tryInsert(worldIn, pos, toInsert, false);
return;
ItemStack remainder = inserter.insert(toInsert, false);
if (remainder.isEmpty()) if (remainder.isEmpty())
itemEntity.remove(); itemEntity.remove();
if (remainder.getCount() < toInsert.getCount()) if (remainder.getCount() < toInsert.getCount())
itemEntity.setItem(remainder); itemEntity.setItem(remainder);
} }
public static ItemStack tryInsert(World worldIn, BlockPos pos, ItemStack toInsert, boolean simulate) {
FilteringBehaviour filter = TileEntityBehaviour.get(worldIn, pos, FilteringBehaviour.TYPE);
InsertingBehaviour inserter = TileEntityBehaviour.get(worldIn, pos, InsertingBehaviour.TYPE);
if (inserter == null)
return toInsert;
if (filter != null && !filter.test(toInsert))
return toInsert;
ItemStack remainder = inserter.insert(toInsert, simulate);
return remainder;
}
@Override @Override
public boolean hasTileEntity(BlockState state) { public boolean hasTileEntity(BlockState state) {
return true; return true;

View file

@ -8,6 +8,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelBlock.Shape; import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelBlock.Shape;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
@ -23,6 +24,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -72,6 +74,41 @@ public class RealityFunnelTileEntity extends SmartTileEntity {
Mode mode = determineCurrentMode(); Mode mode = determineCurrentMode();
if (mode == Mode.BELT) if (mode == Mode.BELT)
tickAsBeltFunnel(); tickAsBeltFunnel();
if (world.isRemote)
return;
if (mode == Mode.CHUTE_SIDE)
tickAsHorizontalChuteFunnel();
if (mode == Mode.CHUTE_END)
tickAsVerticalChuteFunnel();
}
public void tickAsHorizontalChuteFunnel() {
if (!getBlockState().get(ChuteFunnelBlock.PUSHING))
return;
BlockPos chutePos = pos.offset(RealityFunnelBlock.getFunnelFacing(getBlockState()));
TileEntity te = world.getTileEntity(chutePos);
if (!(te instanceof ChuteTileEntity))
return;
ChuteTileEntity chute = (ChuteTileEntity) te;
extracting.setCallback(stack -> chute.setItem(stack, .5f));
extracting.withAdditionalFilter(stack -> chute.getItem()
.isEmpty());
extracting.extract();
}
public void tickAsVerticalChuteFunnel() {
Direction funnelFacing = RealityFunnelBlock.getFunnelFacing(getBlockState());
BlockPos chutePos = pos.offset(funnelFacing);
TileEntity te = world.getTileEntity(chutePos);
if (!(te instanceof ChuteTileEntity))
return;
ChuteTileEntity chute = (ChuteTileEntity) te;
if (chute.getItemMotion() > 0 != (funnelFacing == Direction.UP))
return;
extracting.setCallback(stack -> chute.setItem(stack));
extracting.withAdditionalFilter(stack -> chute.getItem()
.isEmpty());
extracting.extract();
} }
public void tickAsBeltFunnel() { public void tickAsBeltFunnel() {
@ -138,7 +175,7 @@ public class RealityFunnelTileEntity extends SmartTileEntity {
filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()).showCountWhen(() -> { filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()).showCountWhen(() -> {
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
return blockState.getBlock() instanceof HorizontalInteractionFunnelBlock return blockState.getBlock() instanceof HorizontalInteractionFunnelBlock
&& blockState.get(HorizontalInteractionFunnelBlock.PUSHING); && blockState.get(HorizontalInteractionFunnelBlock.PUSHING) || determineCurrentMode() == Mode.CHUTE_END;
}); });
behaviours.add(filtering); behaviours.add(filtering);

View file

@ -97,6 +97,14 @@
"south": {"uv": [9.5, 4, 14.5, 8], "texture": "#13"}, "south": {"uv": [9.5, 4, 14.5, 8], "texture": "#13"},
"down": {"uv": [9.5, 7.5, 14.5, 8], "texture": "#13"} "down": {"uv": [9.5, 7.5, 14.5, 8], "texture": "#13"}
} }
},
{
"from": [3, 13, 3],
"to": [13, 14, 13],
"faces": {
"up": {"uv": [9.5, 9.5, 14.5, 14.5], "texture": "#13"},
"down": {"uv": [9.5, 9.5, 14.5, 14.5], "texture": "#13"}
}
} }
], ],
"groups": [ "groups": [
@ -109,6 +117,5 @@
"name": "ChuteBase", "name": "ChuteBase",
"origin": [8, 8, -7], "origin": [8, 8, -7],
"children": [4, 5, 6, 7] "children": [4, 5, 6, 7]
} }, 8]
]
} }

View file

@ -37,7 +37,7 @@
"rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]}, "rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]},
"faces": { "faces": {
"north": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"}, "north": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"},
"east": {"uv": [13, 0, 16, 11], "texture": "#2"}, "east": {"uv": [13, 11, 16, 0], "texture": "#2"},
"south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"}, "south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"},
"west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"}, "west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"},
"up": {"uv": [5, 10, 11, 13], "rotation": 180, "texture": "#2"} "up": {"uv": [5, 10, 11, 13], "rotation": 180, "texture": "#2"}

View file

@ -68,8 +68,8 @@
"to": [14.1, 10.666, 14.1], "to": [14.1, 10.666, 14.1],
"rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]}, "rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]},
"faces": { "faces": {
"north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"}, "north": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"},
"east": {"uv": [13, 0, 16, 11], "texture": "#2"}, "east": {"uv": [13, 11, 16, 0], "texture": "#2"},
"south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"}, "south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"},
"west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"}, "west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"},
"up": {"uv": [5, 10, 11, 13], "rotation": 180, "texture": "#2"} "up": {"uv": [5, 10, 11, 13], "rotation": 180, "texture": "#2"}
@ -81,7 +81,7 @@
"rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]}, "rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]},
"faces": { "faces": {
"north": {"uv": [1, 3, 11, 10], "rotation": 90, "texture": "#2"}, "north": {"uv": [1, 3, 11, 10], "rotation": 90, "texture": "#2"},
"east": {"uv": [1, 0, 11, 3], "rotation": 270, "texture": "#2"}, "east": {"uv": [0, 0, 10, 3], "rotation": 270, "texture": "#2"},
"south": {"uv": [1, 3, 11, 10], "rotation": 90, "texture": "#2"}, "south": {"uv": [1, 3, 11, 10], "rotation": 90, "texture": "#2"},
"west": {"uv": [1, 0, 11, 3], "rotation": 90, "texture": "#2"} "west": {"uv": [1, 0, 11, 3], "rotation": 90, "texture": "#2"}
} }
@ -90,7 +90,7 @@
"from": [3, 13, 3], "from": [3, 13, 3],
"to": [13, 14, 13], "to": [13, 14, 13],
"faces": { "faces": {
"up": {"uv": [11, 11, 16, 16], "rotation": 180, "texture": "#2"} "up": {"uv": [9.5, 9.5, 14.5, 14.5], "rotation": 180, "texture": "#13"}
} }
} }
], ],

View file

@ -13,7 +13,7 @@
"rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]}, "rotation": {"angle": 45, "axis": "x", "origin": [8, 8, 8]},
"faces": { "faces": {
"north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"}, "north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"east": {"uv": [13, 0, 16, 11], "texture": "#2"}, "east": {"uv": [13, 11, 16, 0], "texture": "#2"},
"south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"}, "south": {"uv": [0, 10, 11, 16], "rotation": 270, "texture": "#2"},
"west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"} "west": {"uv": [13, 0, 16, 11], "rotation": 180, "texture": "#2"}
} }

View file

@ -237,8 +237,53 @@
"south": {"uv": [0, 7, 6, 9.5], "texture": "#13"}, "south": {"uv": [0, 7, 6, 9.5], "texture": "#13"},
"west": {"uv": [0, 7, 6, 9.5], "texture": "#13"} "west": {"uv": [0, 7, 6, 9.5], "texture": "#13"}
} }
},
{
"from": [3, 13, 3],
"to": [13, 14, 13],
"faces": {
"up": {"uv": [9.5, 9.5, 14.5, 14.5], "texture": "#13"},
"down": {"uv": [9.5, 9.5, 14.5, 14.5], "texture": "#13"}
}
} }
], ],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3.25, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"translation": [0, 1, 0],
"scale": [0.5, 0.5, 0.5]
},
"head": {
"rotation": [0, 90, 0]
},
"fixed": {
"rotation": [0, 90, 0],
"translation": [0, 1.5, 0],
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [ "groups": [
{ {
"name": "ChuteTop", "name": "ChuteTop",
@ -254,6 +299,5 @@
"name": "windows", "name": "windows",
"origin": [8, 8, 8], "origin": [8, 8, 8],
"children": [16, 17, 18, 19] "children": [16, 17, 18, 19]
} }, 20]
]
} }

View file

@ -1,138 +0,0 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"13": "create:block/chute",
"particle": "create:block/brass_block"
},
"elements": [
{
"from": [3, 8, 1],
"to": [13, 16, 3],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 16, -3]},
"faces": {
"north": {"uv": [9.5, 0, 14.5, 4], "texture": "#13"},
"south": {"uv": [9.5, 0, 14.5, 4], "texture": "#13"},
"up": {"uv": [1, 0, 6, 1], "texture": "#13"},
"down": {"uv": [1, 6, 6, 7], "texture": "#13"}
}
},
{
"from": [3, 8, 13],
"to": [13, 16, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 16, 19]},
"faces": {
"north": {"uv": [9.5, 0, 14.5, 4], "texture": "#13"},
"south": {"uv": [9.5, 0, 14.5, 4], "texture": "#13"},
"up": {"uv": [1, 0, 6, 1], "rotation": 180, "texture": "#13"},
"down": {"uv": [1, 6, 6, 7], "rotation": 180, "texture": "#13"}
}
},
{
"from": [1, 8, 1],
"to": [3, 16, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [9, 16, 9]},
"faces": {
"north": {"uv": [14.5, 0, 15.5, 4], "texture": "#13"},
"east": {"uv": [8.5, 0, 15.5, 4], "texture": "#13"},
"south": {"uv": [8.5, 0, 9.5, 4], "texture": "#13"},
"west": {"uv": [8.5, 0, 15.5, 4], "texture": "#13"},
"up": {"uv": [0, 0, 1, 7], "texture": "#13"},
"down": {"uv": [0, 0, 1, 7], "texture": "#13"}
}
},
{
"from": [13, 8, 1],
"to": [15, 16, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 16, 7]},
"faces": {
"north": {"uv": [8.5, 0, 9.5, 4], "texture": "#13"},
"east": {"uv": [8.5, 0, 15.5, 4], "texture": "#13"},
"south": {"uv": [14.5, 0, 15.5, 4], "texture": "#13"},
"west": {"uv": [8.5, 0, 15.5, 4], "texture": "#13"},
"up": {"uv": [0, 0, 1, 7], "rotation": 180, "texture": "#13"},
"down": {"uv": [0, 0, 1, 7], "rotation": 180, "texture": "#13"}
}
},
{
"from": [2, 5.7, 2],
"to": [14, 8.7, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -24, 56]},
"faces": {
"north": {"uv": [7.5, 10, 9, 16], "rotation": 90, "texture": "#13"},
"east": {"uv": [7.5, 10, 9, 16], "rotation": 90, "texture": "#13"},
"south": {"uv": [9, 10.5, 15, 14.5], "rotation": 180, "texture": "#13"},
"west": {"uv": [9, 11, 15, 15], "rotation": 180, "texture": "#13"},
"up": {"uv": [9, 9.5, 15, 15.5], "rotation": 180, "texture": "#13"},
"down": {"uv": [9, 11, 15, 15], "rotation": 180, "texture": "#13"}
}
},
{
"from": [2.1, 4, 2.1],
"to": [13.9, 10.666, 13.9],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"east": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"west": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"}
}
},
{
"from": [1.9, -12, 1.9],
"to": [14.1, 4, 14.1],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [9, 8, 15, 16], "texture": "#13"},
"east": {"uv": [9, 8, 15, 16], "texture": "#13"},
"south": {"uv": [9, 8, 15, 16], "texture": "#13"},
"west": {"uv": [9, 8, 15, 16], "texture": "#13"},
"up": {"uv": [9, 9, 15, 15], "texture": "#13"},
"down": {"uv": [9, 9, 15, 15], "texture": "#13"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3.25, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"translation": [0, 1, 0],
"scale": [0.5, 0.5, 0.5]
},
"head": {
"rotation": [0, 90, 0]
},
"fixed": {
"rotation": [0, 90, 0],
"translation": [0, 1.5, 0],
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [
{
"name": "group",
"origin": [8, 56, -56],
"children": [0, 1, 2, 3, 4, 5, 6]
}
]
}

View file

@ -1,77 +0,0 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"13": "create:block/chute",
"particle": "create:block/brass_block"
},
"elements": [
{
"from": [1.9, 4, 1.9],
"to": [14.1, 10.666, 14.1],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"east": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"south": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"west": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"}
}
},
{
"from": [1.9, -12, 1.9],
"to": [14.1, 4, 14.1],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [9, 8, 15, 16], "texture": "#13"},
"east": {"uv": [9, 8, 15, 16], "texture": "#13"},
"south": {"uv": [9, 8, 15, 16], "texture": "#13"},
"west": {"uv": [9, 8, 15, 16], "texture": "#13"},
"down": {"uv": [9, 8, 15, 16], "texture": "#13"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3.25, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"translation": [0, 1, 0],
"scale": [0.5, 0.5, 0.5]
},
"head": {
"rotation": [0, 90, 0]
},
"fixed": {
"rotation": [0, 90, 0],
"translation": [0, 1.5, 0],
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [
{
"name": "group",
"origin": [8, 8, -8],
"children": [0, 1]
}
]
}

View file

@ -1,90 +0,0 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"13": "create:block/chute",
"particle": "create:block/brass_block"
},
"elements": [
{
"from": [2, 8, 2],
"to": [14, 16, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 40]},
"faces": {
"north": {"uv": [9, 11, 15, 15], "rotation": 180, "texture": "#13"},
"east": {"uv": [9, 10.5, 15, 14.5], "rotation": 180, "texture": "#13"},
"south": {"uv": [9, 10.5, 15, 14.5], "rotation": 180, "texture": "#13"},
"west": {"uv": [9, 11, 15, 15], "rotation": 180, "texture": "#13"},
"up": {"uv": [9, 9, 15, 15], "rotation": 180, "texture": "#13"},
"down": {"uv": [9, 11, 15, 15], "rotation": 180, "texture": "#13"}
}
},
{
"from": [1.9, 4, 1.9],
"to": [14.1, 10.666, 14.1],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"east": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"south": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"},
"west": {"uv": [6, 10, 9, 16], "rotation": 90, "texture": "#13"}
}
},
{
"from": [1.9, -12, 1.9],
"to": [14.1, 4, 14.1],
"rotation": {"angle": -45, "axis": "x", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [9, 8, 15, 16], "texture": "#13"},
"east": {"uv": [9, 8, 15, 16], "texture": "#13"},
"south": {"uv": [9, 8, 15, 16], "texture": "#13"},
"west": {"uv": [9, 8, 15, 16], "texture": "#13"},
"down": {"uv": [9, 9, 15, 15], "texture": "#13"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3.25, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"translation": [0, 1, 0],
"scale": [0.5, 0.5, 0.5]
},
"head": {
"rotation": [0, 90, 0]
},
"fixed": {
"rotation": [0, 90, 0],
"translation": [0, 1.5, 0],
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [
{
"name": "group",
"origin": [8, 24, -24],
"children": [0, 1, 2]
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5,8 +5,8 @@
"3": "create:block/belt_funnel_push_off", "3": "create:block/belt_funnel_push_off",
"4": "create:block/funnel_plating", "4": "create:block/funnel_plating",
"13": "create:block/chute", "13": "create:block/chute",
"3_particle": "create:block/brass_block",
"particle": "create:block/brass_block", "particle": "create:block/brass_block",
"3_particle": "create:block/brass_block",
"1_2": "create:block/funnel_back" "1_2": "create:block/funnel_back"
}, },
"elements": [ "elements": [
@ -138,8 +138,8 @@
}, },
{ {
"name": "Back", "name": "Back",
"from": [1.1, 1.1, -2.9], "from": [1.1, 1.1, -3.1],
"to": [14.9, 14.9, 2.1], "to": [14.9, 14.9, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 6]}, "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 6]},
"faces": { "faces": {
"north": {"uv": [8.5, 8.5, 15.5, 15.5], "texture": "#13"}, "north": {"uv": [8.5, 8.5, 15.5, 15.5], "texture": "#13"},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB