Distribu-tunnel

- Fixed dynamic Mechanical Arm parts not being lit correctly
- Fixed Mechanical Arm not always initializing interaction points on the client
- Belt tunnels now create side-openings for belt-like blocks such as the depot
- Belt tunnels no longer create flaps when there is a belt funnel connected to that side
- Brass tunnels can now distribute items among their output sides and other connected tunnels, taking into account their sided filtering
This commit is contained in:
simibubi 2020-07-09 21:55:14 +02:00
parent 26112ddc93
commit 16e08a0693
9 changed files with 393 additions and 91 deletions

View file

@ -57,6 +57,7 @@ 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;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
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;
import net.minecraft.world.WorldType; import net.minecraft.world.WorldType;
@ -212,11 +213,6 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
return slope != BeltSlope.VERTICAL && slope != BeltSlope.SIDEWAYS; return slope != BeltSlope.VERTICAL && slope != BeltSlope.SIDEWAYS;
} }
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
updateNeighbouringTunnel(worldIn, pos, state);
}
@Override @Override
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn, public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand handIn,
BlockRayTraceResult hit) { BlockRayTraceResult hit) {
@ -476,9 +472,6 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
return; return;
if (state.getBlock() == newState.getBlock()) if (state.getBlock() == newState.getBlock())
return; return;
updateNeighbouringTunnel(world, pos, state);
if (isMoving) if (isMoving)
return; return;
TileEntity belt = world.getTileEntity(pos); TileEntity belt = world.getTileEntity(pos);
@ -512,17 +505,19 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
world.playEvent(2001, currentPos, Block.getStateId(currentState)); world.playEvent(2001, currentPos, Block.getStateId(currentState));
} }
} }
@Override
public BlockState updatePostPlacement(BlockState state, Direction side, BlockState p_196271_3_,
IWorld world, BlockPos pos, BlockPos p_196271_6_) {
if (side.getAxis().isHorizontal())
updateTunnelConnections(world, pos.up());
return state;
}
private void updateNeighbouringTunnel(World world, BlockPos pos, BlockState beltState) { private void updateTunnelConnections(IWorld world, BlockPos pos) {
boolean isEnd = beltState.get(PART) != BeltPart.END; Block tunnelBlock = world.getBlockState(pos).getBlock();
if (isEnd && beltState.get(PART) != BeltPart.START) if (tunnelBlock instanceof BeltTunnelBlock)
return; ((BeltTunnelBlock) tunnelBlock).updateTunnel(world, pos);
int offset = isEnd ? -1 : 1;
BlockPos tunnelPos = pos.offset(beltState.get(HORIZONTAL_FACING), offset)
.up();
Block adjacent = world.getBlockState(tunnelPos).getBlock();
if (adjacent instanceof BeltTunnelBlock)
((BeltTunnelBlock) adjacent).updateTunnel(world, tunnelPos);
} }
public static List<BlockPos> getBeltChain(World world, BlockPos controllerPos) { public static List<BlockPos> getBeltChain(World world, BlockPos controllerPos) {

View file

@ -19,6 +19,7 @@ import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMoveme
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler;
import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment; import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment;
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.belts.tunnel.BrassTunnelTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour;
@ -79,7 +80,6 @@ public class BeltTileEntity extends KineticTileEntity {
public void addBehaviours(List<TileEntityBehaviour> behaviours) { public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours); super.addBehaviours(behaviours);
behaviours.add(new DirectBeltInputBehaviour(this) behaviours.add(new DirectBeltInputBehaviour(this)
.onlyInsertWhen(d -> getSpeed() != 0 && getMovementFacing() != d.getOpposite())
.setInsertionHandler(this::tryInsertingFromSide)); .setInsertionHandler(this::tryInsertingFromSide));
behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
.withStackPlacement(this::getWorldPositionOf)); .withStackPlacement(this::getWorldPositionOf));
@ -397,13 +397,31 @@ public class BeltTileEntity extends KineticTileEntity {
BeltTileEntity nextBeltController = getControllerTE(); BeltTileEntity nextBeltController = getControllerTE();
ItemStack inserted = transportedStack.stack; ItemStack inserted = transportedStack.stack;
ItemStack empty = ItemStack.EMPTY; ItemStack empty = ItemStack.EMPTY;
if (nextBeltController == null) if (nextBeltController == null)
return inserted; return inserted;
BeltInventory nextInventory = nextBeltController.getInventory(); BeltInventory nextInventory = nextBeltController.getInventory();
TileEntity teAbove = world.getTileEntity(pos.up());
if (teAbove instanceof BrassTunnelTileEntity) {
BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) teAbove;
if (tunnelTE.hasDistributionBehaviour()) {
if (!tunnelTE.getStackToDistribute().isEmpty())
return inserted;
if (!tunnelTE.testFlapFilter(side.getOpposite(), inserted))
return inserted;
if (!simulate) {
BeltTunnelInteractionHandler.flapTunnel(nextInventory, index, side.getOpposite(), true);
tunnelTE.setStackToDistribute(inserted);
}
return empty;
}
}
if (getSpeed() == 0) if (getSpeed() == 0)
return inserted; return inserted;
if (getMovementFacing() == side.getOpposite())
return inserted;
if (!nextInventory.canInsertAtFromSide(index, side)) if (!nextInventory.canInsertAtFromSide(index, side))
return inserted; return inserted;
if (simulate) if (simulate)

View file

@ -28,13 +28,35 @@ public class BeltTunnelInteractionHandler {
upcomingSegment = -1; upcomingSegment = -1;
if (currentSegment != upcomingSegment) { if (currentSegment != upcomingSegment) {
if (stuckAtTunnel(beltInventory, upcomingSegment, current.stack, movementFacing)) { if (stuckAtTunnel(beltInventory, upcomingSegment, current.stack, movementFacing)) {
current.beltPosition = currentSegment + (beltInventory.beltMovementPositive ? .99f : -.01f); current.beltPosition = currentSegment + (beltInventory.beltMovementPositive ? .99f : .01f);
return true; return true;
} }
if (!beltInventory.belt.getWorld().isRemote) { boolean onServer = !beltInventory.belt.getWorld().isRemote;
boolean removed = false;
BeltTunnelTileEntity nextTunnel = getTunnelOnSegement(beltInventory, upcomingSegment);
if (nextTunnel instanceof BrassTunnelTileEntity) {
BrassTunnelTileEntity brassTunnel = (BrassTunnelTileEntity) nextTunnel;
if (brassTunnel.hasDistributionBehaviour()) {
if (!brassTunnel.getStackToDistribute()
.isEmpty())
return true;
if (onServer) {
brassTunnel.setStackToDistribute(current.stack);
current.stack = ItemStack.EMPTY;
beltInventory.belt.sendData();
beltInventory.belt.markDirty();
}
removed = true;
}
}
if (onServer) {
flapTunnel(beltInventory, currentSegment, movementFacing, false); flapTunnel(beltInventory, currentSegment, movementFacing, false);
flapTunnel(beltInventory, upcomingSegment, movementFacing.getOpposite(), true); flapTunnel(beltInventory, upcomingSegment, movementFacing.getOpposite(), true);
} }
if (removed)
return true;
} }
return false; return false;
@ -58,21 +80,28 @@ public class BeltTunnelInteractionHandler {
} }
public static void flapTunnel(BeltInventory beltInventory, int offset, Direction side, boolean inward) { public static void flapTunnel(BeltInventory beltInventory, int offset, Direction side, boolean inward) {
BeltTunnelTileEntity te = getTunnelOnSegement(beltInventory, offset);
if (te == null)
return;
te.flap(side, inward ^ side.getAxis() == Axis.Z);
}
protected static BeltTunnelTileEntity getTunnelOnSegement(BeltInventory beltInventory, int offset) {
BeltTileEntity belt = beltInventory.belt; BeltTileEntity belt = beltInventory.belt;
if (belt.getBlockState() if (belt.getBlockState()
.get(BeltBlock.SLOPE) != BeltSlope.HORIZONTAL) .get(BeltBlock.SLOPE) != BeltSlope.HORIZONTAL)
return; return null;
BlockPos pos = BeltHelper.getPositionForOffset(belt, offset) BlockPos pos = BeltHelper.getPositionForOffset(belt, offset)
.up(); .up();
if (!(belt.getWorld() if (!(belt.getWorld()
.getBlockState(pos) .getBlockState(pos)
.getBlock() instanceof BeltTunnelBlock)) .getBlock() instanceof BeltTunnelBlock))
return; return null;
TileEntity te = belt.getWorld() TileEntity te = belt.getWorld()
.getTileEntity(pos); .getTileEntity(pos);
if (te == null || !(te instanceof BeltTunnelTileEntity)) if (te == null || !(te instanceof BeltTunnelTileEntity))
return; return null;
((BeltTunnelTileEntity) te).flap(side, inward ^ side.getAxis() == Axis.Z); return ((BeltTunnelTileEntity) te);
} }
} }

View file

@ -7,6 +7,8 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltSlope;
import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.foundation.block.ITE; 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.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld;
@ -122,7 +124,7 @@ public class BeltTunnelBlock extends Block implements ITE<BeltTunnelTileEntity>,
return tunnelState; return tunnelState;
} }
public void updateTunnel(World world, BlockPos pos) { public void updateTunnel(IWorld world, BlockPos pos) {
BlockState tunnel = world.getBlockState(pos); BlockState tunnel = world.getBlockState(pos);
BlockState newTunnel = getTunnelState(world, pos); BlockState newTunnel = getTunnelState(world, pos);
if (tunnel != newTunnel) { if (tunnel != newTunnel) {
@ -144,14 +146,8 @@ public class BeltTunnelBlock extends Block implements ITE<BeltTunnelTileEntity>,
// T and Cross // T and Cross
Direction left = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis) Direction left = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis)
.rotateY(); .rotateY();
BlockState leftState = reader.getBlockState(pos.offset(left) boolean onLeft = hasValidOutput(reader, pos.down(), left);
.down()); boolean onRight = hasValidOutput(reader, pos.down(), left.getOpposite());
boolean onLeft = AllBlocks.BELT.has(leftState) && leftState.get(BeltBlock.HORIZONTAL_FACING)
.getAxis() != axis;
BlockState rightState = reader.getBlockState(pos.offset(left.getOpposite())
.down());
boolean onRight = AllBlocks.BELT.has(rightState) && rightState.get(BeltBlock.HORIZONTAL_FACING)
.getAxis() != axis;
if (onLeft && onRight) if (onLeft && onRight)
state = state.with(SHAPE, Shape.CROSS); state = state.with(SHAPE, Shape.CROSS);
@ -178,6 +174,15 @@ public class BeltTunnelBlock extends Block implements ITE<BeltTunnelTileEntity>,
return state; return state;
} }
private boolean hasValidOutput(IBlockReader world, BlockPos pos, Direction side) {
BlockState blockState = world.getBlockState(pos.offset(side));
if (AllBlocks.BELT.has(blockState))
return blockState.get(BeltBlock.HORIZONTAL_FACING).getAxis() == side.getAxis();
DirectBeltInputBehaviour behaviour =
TileEntityBehaviour.get(world, pos.offset(side), DirectBeltInputBehaviour.TYPE);
return behaviour != null && behaviour.canInsertFromSide(side);
}
@Override @Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) { public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
if (!hasWindow(state)) if (!hasWindow(state))

View file

@ -10,6 +10,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
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;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
@ -130,6 +131,12 @@ public class BeltTunnelTileEntity extends SmartTileEntity {
if (!positive && shape == Shape.T_RIGHT) if (!positive && shape == Shape.T_RIGHT)
continue; continue;
} }
BlockState funnelState = world.getBlockState(getPos().offset(direction));
if (funnelState.getBlock() instanceof BeltFunnelBlock)
if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite())
continue;
flaps.put(direction, new InterpolatedChasingValue().start(.25f) flaps.put(direction, new InterpolatedChasingValue().start(.25f)
.target(0) .target(0)
.withSpeed(.05f)); .withSpeed(.05f));

View file

@ -0,0 +1,59 @@
package com.simibubi.create.content.logistics.block.belts.tunnel;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
public class BrassTunnelItemHandler implements IItemHandler {
private BrassTunnelTileEntity te;
public BrassTunnelItemHandler(BrassTunnelTileEntity te) {
this.te = te;
}
@Override
public int getSlots() {
return 1;
}
@Override
public ItemStack getStackInSlot(int slot) {
return te.stackToDistribute;
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (!te.hasDistributionBehaviour()) {
LazyOptional<IItemHandler> beltCapability = te.getBeltCapability();
if (!beltCapability.isPresent())
return stack;
return beltCapability.orElse(null).insertItem(slot, stack, simulate);
}
if (!te.stackToDistribute.isEmpty())
return stack;
if (!simulate)
te.setStackToDistribute(stack);
return ItemStack.EMPTY;
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
LazyOptional<IItemHandler> beltCapability = te.getBeltCapability();
if (!beltCapability.isPresent())
return ItemStack.EMPTY;
return beltCapability.orElse(null).extractItem(slot, amount, simulate);
}
@Override
public int getSlotLimit(int slot) {
return te.stackToDistribute.isEmpty() ? 64 : te.stackToDistribute.getMaxStackSize();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
}
}

View file

@ -10,6 +10,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.BeltHelper; import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
@ -17,7 +18,9 @@ import com.simibubi.create.foundation.tileEntity.behaviour.filtering.SidedFilter
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
@ -27,7 +30,12 @@ import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class BrassTunnelTileEntity extends BeltTunnelTileEntity { public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
@ -42,26 +50,170 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
int distributionDistanceLeft; int distributionDistanceLeft;
int distributionDistanceRight; int distributionDistanceRight;
private LazyOptional<IItemHandler> beltCapability;
private LazyOptional<IItemHandler> tunnelCapability;
public BrassTunnelTileEntity(TileEntityType<? extends BeltTunnelTileEntity> type) { public BrassTunnelTileEntity(TileEntityType<? extends BeltTunnelTileEntity> type) {
super(type); super(type);
distributionTargets = new ArrayList<>(); distributionTargets = new ArrayList<>();
stackToDistribute = ItemStack.EMPTY; stackToDistribute = ItemStack.EMPTY;
beltCapability = LazyOptional.empty();
tunnelCapability = LazyOptional.of(() -> new BrassTunnelItemHandler(this));
} }
// @Override @Override
// public void tick() { public void tick() {
// super.tick(); super.tick();
// BeltTileEntity beltBelow = BeltHelper.getSegmentTE(world, pos.down());
// if (stackToDistribute.isEmpty())
// return; if (beltBelow == null || beltBelow.getSpeed() == 0)
// if (distributionProgress == -1) { return;
// distributionTargets.clear(); if (stackToDistribute.isEmpty())
// for (Pair<BrassTunnelTileEntity, Direction> pair : gatherValidOutputs()) { return;
// if (world.isRemote)
// } return;
// }
// if (distributionProgress == -1) {
// } distributionTargets.clear();
distributionDistanceLeft = 0;
distributionDistanceRight = 0;
for (Pair<BrassTunnelTileEntity, Direction> pair : gatherValidOutputs()) {
BrassTunnelTileEntity tunnel = pair.getKey();
Direction output = pair.getValue();
if (!insertIntoTunnel(tunnel, output, stackToDistribute, true).isEmpty())
continue;
distributionTargets.add(Pair.of(tunnel.pos, output));
int distance = tunnel.pos.getX() + tunnel.pos.getZ() - pos.getX() - pos.getZ();
if (distance < 0)
distributionDistanceLeft = Math.max(distributionDistanceLeft, -distance);
else
distributionDistanceRight = Math.max(distributionDistanceRight, distance);
}
if (distributionTargets.isEmpty())
return;
distributionProgress = 0;
sendData();
return;
}
// TODO this is instant for now
if (distributionProgress == 0) {
List<Pair<BrassTunnelTileEntity, Direction>> validTargets = new ArrayList<>();
for (Pair<BlockPos, Direction> pair : distributionTargets) {
BlockPos tunnelPos = pair.getKey();
Direction output = pair.getValue();
TileEntity te = world.getTileEntity(tunnelPos);
if (!(te instanceof BrassTunnelTileEntity))
continue;
validTargets.add(Pair.of((BrassTunnelTileEntity) te, output));
}
if (validTargets.size() == 0) {
distributionProgress = -1;
sendData();
return;
}
int stackSizeBefore = stackToDistribute.getCount();
int stackSizeForOutput = stackSizeBefore / validTargets.size();
int remainder = stackSizeBefore % validTargets.size();
for (Pair<BrassTunnelTileEntity, Direction> pair : validTargets) {
BrassTunnelTileEntity tunnel = pair.getKey();
Direction side = pair.getValue();
int stackSize = stackSizeForOutput + (remainder > 0 ? 1 : 0);
ItemStack toOutput = stackToDistribute.copy()
.split(stackSize);
if (!insertIntoTunnel(tunnel, side, toOutput, false).isEmpty())
continue;
stackToDistribute.shrink(stackSize);
remainder--;
}
distributionProgress = -1;
markDirty();
sendData();
return;
}
}
public void setStackToDistribute(ItemStack stack) {
stackToDistribute = stack;
distributionProgress = -1;
sendData();
markDirty();
}
public ItemStack getStackToDistribute() {
return stackToDistribute;
}
protected ItemStack insertIntoTunnel(BrassTunnelTileEntity tunnel, Direction side, ItemStack stack,
boolean simulate) {
if (stack.isEmpty())
return stack;
if (!tunnel.testFlapFilter(side, stack))
return stack;
BeltTileEntity below = BeltHelper.getSegmentTE(world, tunnel.pos.down());
if (below == null)
return stack;
BlockPos offset = tunnel.getPos()
.down()
.offset(side);
DirectBeltInputBehaviour sideOutput = TileEntityBehaviour.get(world, offset, DirectBeltInputBehaviour.TYPE);
if (sideOutput != null) {
ItemStack result = sideOutput.handleInsertion(stack, side, simulate);
if (result.isEmpty() && !simulate)
tunnel.flap(side, true);
return result;
}
Direction movementFacing = below.getMovementFacing();
if (side == movementFacing)
if (!Block.hasSolidSide(world.getBlockState(offset), world, offset, side.getOpposite())) {
BeltTileEntity controllerTE = below.getControllerTE();
if (controllerTE == null)
return stack;
if (!simulate) {
tunnel.flap(side, true);
ItemStack ejected = stack;
float beltMovementSpeed = below.getDirectionAwareBeltMovementSpeed();
float movementSpeed = Math.max(Math.abs(beltMovementSpeed), 1 / 8f);
int additionalOffset = beltMovementSpeed > 0 ? 1 : 0;
Vec3d outPos = BeltHelper.getVectorForOffset(controllerTE, below.index + additionalOffset);
Vec3d outMotion = new Vec3d(side.getDirectionVec()).scale(movementSpeed)
.add(0, 1 / 8f, 0);
outPos.add(outMotion.normalize());
ItemEntity entity = new ItemEntity(world, outPos.x, outPos.y + 6 / 16f, outPos.z, ejected);
entity.setMotion(outMotion);
entity.setDefaultPickupDelay();
entity.velocityChanged = true;
world.addEntity(entity);
}
return ItemStack.EMPTY;
}
return stack;
}
public boolean testFlapFilter(Direction side, ItemStack stack) {
if (filtering == null)
return false;
if (filtering.get(side) == null) {
FilteringBehaviour adjacentFilter =
TileEntityBehaviour.get(world, pos.offset(side), FilteringBehaviour.TYPE);
if (adjacentFilter == null)
return true;
return adjacentFilter.test(stack);
}
return filtering.test(side, stack);
}
@Override @Override
public void initialize() { public void initialize() {
@ -75,20 +227,26 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
public boolean canInsert(Direction side, ItemStack stack) { public boolean canInsert(Direction side, ItemStack stack) {
if (filtering != null && !filtering.test(side, stack)) if (filtering != null && !filtering.test(side, stack))
return false; return false;
if (!connectedLeft && !connectedRight) if (!hasDistributionBehaviour())
return true; return true;
if (!stackToDistribute.isEmpty()) if (!stackToDistribute.isEmpty())
return false; return false;
return true; return true;
} }
public boolean onItemInserted(ItemStack stack) { public boolean hasDistributionBehaviour() {
if (!connectedLeft && !connectedRight) if (flaps.isEmpty())
return false; return false;
stackToDistribute = stack.copy(); if (connectedLeft || connectedRight)
sendData(); return true;
markDirty(); BlockState blockState = getBlockState();
return true; if (!AllBlocks.BRASS_TUNNEL.has(blockState))
return false;
Axis axis = blockState.get(BrassTunnelBlock.HORIZONTAL_AXIS);
for (Direction direction : flaps.keySet())
if (direction.getAxis() != axis)
return true;
return false;
} }
private List<Pair<BrassTunnelTileEntity, Direction>> gatherValidOutputs() { private List<Pair<BrassTunnelTileEntity, Direction>> gatherValidOutputs() {
@ -112,27 +270,41 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
BeltTileEntity below = BeltHelper.getSegmentTE(world, tunnelTE.pos.down()); BeltTileEntity below = BeltHelper.getSegmentTE(world, tunnelTE.pos.down());
if (below == null) if (below == null)
return; return;
if (below.getSpeed() != 0) { Direction movementFacing = below.getMovementFacing();
Direction direction = below.getMovementFacing();
if (tunnelTE.flaps.containsKey(direction))
validOutputs.add(Pair.of(tunnelTE, direction));
}
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
if (!AllBlocks.BRASS_TUNNEL.has(blockState)) if (!AllBlocks.BRASS_TUNNEL.has(blockState))
return; return;
for (boolean left : Iterate.trueAndFalse) {
Axis axis = blockState.get(BrassTunnelBlock.HORIZONTAL_AXIS); for (Direction direction : Iterate.horizontalDirections) {
Direction baseDirection = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); if (direction == movementFacing && below.getSpeed() == 0)
Direction direction = left ? baseDirection.rotateYCCW() : baseDirection.rotateY(); continue;
if (tunnelTE.flaps.containsKey(direction)) { if (tunnelTE.flaps.containsKey(direction) || tunnelTE.hasValidOutputFunnel(direction)) {
DirectBeltInputBehaviour inputBehaviour = TileEntityBehaviour.get(world, tunnelTE.pos.down() BlockPos offset = tunnelTE.pos.down()
.offset(direction), DirectBeltInputBehaviour.TYPE); .offset(direction);
DirectBeltInputBehaviour inputBehaviour =
TileEntityBehaviour.get(world, offset, DirectBeltInputBehaviour.TYPE);
if (inputBehaviour == null) {
if (direction == movementFacing)
if (!Block.hasSolidSide(world.getBlockState(offset), world, offset, direction.getOpposite()))
validOutputs.add(Pair.of(tunnelTE, direction));
continue;
}
if (inputBehaviour.canInsertFromSide(direction)) if (inputBehaviour.canInsertFromSide(direction))
validOutputs.add(Pair.of(tunnelTE, direction)); validOutputs.add(Pair.of(tunnelTE, direction));
continue;
} }
} }
}
protected boolean hasValidOutputFunnel(Direction side) {
BlockState funnelState = world.getBlockState(getPos().offset(side));
if (!(funnelState.getBlock() instanceof BeltFunnelBlock))
return false;
if (funnelState.has(BeltFunnelBlock.POWERED) && funnelState.get(BeltFunnelBlock.POWERED))
return false;
if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) != side.getOpposite())
return false;
return !funnelState.get(BeltFunnelBlock.PUSHING);
} }
@Override @Override
@ -270,4 +442,26 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
return (BrassTunnelTileEntity) adjacentTE; return (BrassTunnelTileEntity) adjacentTE;
} }
@Override
public void remove() {
tunnelCapability.invalidate();
super.remove();
}
@Override
public <T> LazyOptional<T> getCapability(Capability<T> capability, Direction side) {
if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return tunnelCapability.cast();
return super.getCapability(capability, side);
}
public LazyOptional<IItemHandler> getBeltCapability() {
if (!beltCapability.isPresent()) {
TileEntity tileEntity = world.getTileEntity(pos.down());
if (tileEntity != null)
beltCapability = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
}
return beltCapability;
}
} }

View file

@ -37,12 +37,12 @@ public class ArmRenderer extends KineticTileEntityRenderer {
ms.push(); ms.push();
SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState); SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light);
SuperByteBuffer lowerBody = AllBlockPartials.ARM_LOWER_BODY.renderOn(blockState); SuperByteBuffer lowerBody = AllBlockPartials.ARM_LOWER_BODY.renderOn(blockState).light(light);
SuperByteBuffer upperBody = AllBlockPartials.ARM_UPPER_BODY.renderOn(blockState); SuperByteBuffer upperBody = AllBlockPartials.ARM_UPPER_BODY.renderOn(blockState).light(light);
SuperByteBuffer head = AllBlockPartials.ARM_HEAD.renderOn(blockState); SuperByteBuffer head = AllBlockPartials.ARM_HEAD.renderOn(blockState).light(light);
SuperByteBuffer claw = AllBlockPartials.ARM_CLAW_BASE.renderOn(blockState); SuperByteBuffer claw = AllBlockPartials.ARM_CLAW_BASE.renderOn(blockState).light(light);
SuperByteBuffer clawGrip = AllBlockPartials.ARM_CLAW_GRIP.renderOn(blockState); SuperByteBuffer clawGrip = AllBlockPartials.ARM_CLAW_GRIP.renderOn(blockState).light(light);
msr.centre(); msr.centre();

View file

@ -186,12 +186,12 @@ public class ArmTileEntity extends KineticTileEntity {
protected void collectItem() { protected void collectItem() {
ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint();
if (armInteractionPoint != null) 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)
continue; continue;
heldItem = armInteractionPoint.extract(world, i, amountExtracted, false); heldItem = armInteractionPoint.extract(world, i, amountExtracted, false);
phase = Phase.SEARCH_OUTPUTS; phase = Phase.SEARCH_OUTPUTS;
chasedPointProgress = 0; chasedPointProgress = 0;
@ -200,7 +200,7 @@ public class ArmTileEntity extends KineticTileEntity {
markDirty(); markDirty();
return; return;
} }
phase = Phase.SEARCH_INPUTS; phase = Phase.SEARCH_INPUTS;
chasedPointProgress = 0; chasedPointProgress = 0;
chasedPointIndex = -1; chasedPointIndex = -1;
@ -218,7 +218,7 @@ public class ArmTileEntity extends KineticTileEntity {
} }
protected void initInteractionPoints() { protected void initInteractionPoints() {
if (interactionPointTag == null) if (!updateInteractionPoints || interactionPointTag == null)
return; return;
inputs.clear(); inputs.clear();
outputs.clear(); outputs.clear();
@ -231,9 +231,9 @@ public class ArmTileEntity extends KineticTileEntity {
if (point.mode == Mode.TAKE) if (point.mode == Mode.TAKE)
inputs.add(point); inputs.add(point);
} }
interactionPointTag = null; updateInteractionPoints = false;
markDirty();
sendData(); sendData();
markDirty();
} }
@Override @Override
@ -249,7 +249,7 @@ public class ArmTileEntity extends KineticTileEntity {
.forEach(pointsNBT::add); .forEach(pointsNBT::add);
NBTHelper.writeEnum(compound, "Phase", phase); NBTHelper.writeEnum(compound, "Phase", phase);
compound.put("InterationPoints", pointsNBT); compound.put("InteractionPoints", pointsNBT);
compound.put("HeldItem", heldItem.serializeNBT()); compound.put("HeldItem", heldItem.serializeNBT());
compound.putInt("TargetPointIndex", chasedPointIndex); compound.putInt("TargetPointIndex", chasedPointIndex);
compound.putFloat("MovementProgress", chasedPointProgress); compound.putFloat("MovementProgress", chasedPointProgress);
@ -259,8 +259,6 @@ public class ArmTileEntity extends KineticTileEntity {
@Override @Override
public CompoundNBT writeToClient(CompoundNBT compound) { public CompoundNBT writeToClient(CompoundNBT compound) {
super.writeToClient(compound); super.writeToClient(compound);
if (interactionPointTag != null)
compound.put("InitialInterationPoints", interactionPointTag);
return compound; return compound;
} }
@ -271,19 +269,19 @@ public class ArmTileEntity extends KineticTileEntity {
phase = NBTHelper.readEnum(compound, "Phase", Phase.class); phase = NBTHelper.readEnum(compound, "Phase", Phase.class);
chasedPointIndex = compound.getInt("TargetPointIndex"); chasedPointIndex = compound.getInt("TargetPointIndex");
chasedPointProgress = compound.getFloat("MovementProgress"); chasedPointProgress = compound.getFloat("MovementProgress");
interactionPointTag = compound.getList("InteractionPoints", NBT.TAG_COMPOUND);
if (!hasWorld() || !world.isRemote || updateInteractionPoints)
interactionPointTag = compound.getList("InterationPoints", NBT.TAG_COMPOUND);
updateInteractionPoints = false;
} }
@Override @Override
public void readClientUpdate(CompoundNBT tag) { public void readClientUpdate(CompoundNBT tag) {
int previousIndex = chasedPointIndex; int previousIndex = chasedPointIndex;
Phase previousPhase = phase; Phase previousPhase = phase;
ListNBT interactionPointTagBefore = interactionPointTag;
super.readClientUpdate(tag); super.readClientUpdate(tag);
if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size())
updateInteractionPoints = true;
if (previousIndex != chasedPointIndex || (previousPhase != phase)) { if (previousIndex != chasedPointIndex || (previousPhase != phase)) {
ArmInteractionPoint previousPoint = null; ArmInteractionPoint previousPoint = null;
if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size()) if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size())
@ -294,9 +292,6 @@ public class ArmTileEntity extends KineticTileEntity {
if (previousPoint != null) if (previousPoint != null)
previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle; previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle;
} }
if (tag.contains("InitialInterationPoints"))
interactionPointTag = tag.getList("InitialInterationPoints", NBT.TAG_COMPOUND);
} }
} }