Reworked belt processing and interfacing

- Removed the IBeltAttachment system
- Item processing on belts is now a TE behaviour
- Added TE behaviour for allowing belts (and similar) to directly insert items
- Massive refactor to the Belts' inventory
- Fixed fast moving items missing their processing step
- Saws, Basins, Crushing Wheels, Belts and Crafters now interact through the new behaviour rather than hard-coded interactions
- Fixed items (visually) disappearing on saws while queueing up
- Items on belts now back up a little further away from the end of the belt
This commit is contained in:
simibubi 2020-06-26 21:38:10 +02:00
parent 69dd19cd58
commit 9fe1d85199
34 changed files with 753 additions and 1068 deletions

View file

@ -5,6 +5,7 @@ import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlo
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.lang3.tuple.Pair;
@ -13,8 +14,8 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InventoryManagementBehaviour.Attachments;
@ -27,7 +28,6 @@ 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;
@ -91,9 +91,9 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
setLazyTickRate(20);
phase = Phase.IDLE;
groupedItemsBeforeCraft = new GroupedItems();
// Does not get serialized due to active checking in tick
wasPoweredBefore = true;
wasPoweredBefore = true;
}
@Override
@ -337,13 +337,13 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
}
protected boolean isTargetingBelt() {
DirectBeltInputBehaviour behaviour = getTargetingBelt();
return behaviour != null && behaviour.canInsertFromSide(getTargetFacing());
}
protected DirectBeltInputBehaviour getTargetingBelt() {
BlockPos targetPos = pos.offset(getTargetFacing());
if (!AllBlocks.BELT.has(world.getBlockState(targetPos)))
return false;
TileEntity te = world.getTileEntity(targetPos);
if (!(te instanceof BeltTileEntity))
return false;
return ((KineticTileEntity) te).getSpeed() != 0;
return TileEntityBehaviour.get(world, targetPos, DirectBeltInputBehaviour.TYPE);
}
public void tryInsert() {
@ -355,22 +355,21 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
boolean chagedPhase = phase != Phase.INSERTING;
final List<Pair<Integer, Integer>> inserted = new LinkedList<>();
groupedItems.grid.forEach((pair, stack) -> {
if (isTargetingBelt()) {
Direction facing = getTargetFacing();
BlockPos targetPos = pos.offset(facing);
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(targetPos);
if (te.tryInsertingFromSide(facing, stack, false))
inserted.add(pair);
return;
}
DirectBeltInputBehaviour behaviour = getTargetingBelt();
for (Entry<Pair<Integer, Integer>, ItemStack> entry : groupedItems.grid.entrySet()) {
Pair<Integer, Integer> pair = entry.getKey();
ItemStack stack = entry.getValue();
Direction facing = getTargetFacing();
ItemStack remainder = inserting.insert(stack.copy(), false);
if (!remainder.isEmpty())
ItemStack remainder = behaviour == null ? inserting.insert(stack.copy(), false)
: behaviour.handleInsertion(stack, facing, false);
if (!remainder.isEmpty()) {
stack.setCount(remainder.getCount());
else
inserted.add(pair);
});
continue;
}
inserted.add(pair);
}
inserted.forEach(groupedItems.grid::remove);
if (groupedItems.grid.isEmpty())

View file

@ -11,7 +11,9 @@ import com.simibubi.create.content.contraptions.processing.ProcessingInventory;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.SyncedTileEntity;
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.VecHelper;
import net.minecraft.entity.Entity;
@ -24,7 +26,6 @@ import net.minecraft.particles.BlockParticleData;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
@ -36,7 +37,7 @@ import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.RecipeWrapper;
public class CrushingWheelControllerTileEntity extends SyncedTileEntity implements ITickableTileEntity {
public class CrushingWheelControllerTileEntity extends SmartTileEntity {
public Entity processingEntity;
private UUID entityUUID;
@ -60,14 +61,20 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
wrapper = new RecipeWrapper(inventory);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this));
}
@Override
public void tick() {
super.tick();
if (isFrozen())
return;
if (searchForEntity) {
searchForEntity = false;
List<Entity> search = world.getEntitiesInAABBexcluding(null, new AxisAlignedBB(getPos()),
e -> entityUUID.equals(e.getUniqueID()));
e -> entityUUID.equals(e.getUniqueID()));
if (search.isEmpty())
clear();
else
@ -84,9 +91,9 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
if (!hasEntity()) {
float processingSpeed = MathHelper.clamp(
(speed) / (!inventory.appliedRecipe ? MathHelper.log2(inventory.getStackInSlot(0).getCount()) : 1),
.25f, 20);
float processingSpeed =
MathHelper.clamp((speed) / (!inventory.appliedRecipe ? MathHelper.log2(inventory.getStackInSlot(0)
.getCount()) : 1), .25f, 20);
inventory.remainingTime -= processingSpeed;
spawnParticles(inventory.getStackInSlot(0));
@ -107,7 +114,8 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
continue;
ItemEntity entityIn = new ItemEntity(world, outPos.x, outPos.y, outPos.z, stack);
entityIn.setMotion(Vec3d.ZERO);
entityIn.getPersistentData().put("BypassCrushingWheel", NBTUtil.writeBlockPos(pos));
entityIn.getPersistentData()
.put("BypassCrushingWheel", NBTUtil.writeBlockPos(pos));
world.addEntity(entityIn);
}
inventory.clear();
@ -118,8 +126,8 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
return;
}
if (!processingEntity.isAlive()
|| !processingEntity.getBoundingBox().intersects(new AxisAlignedBB(pos).grow(.5f))) {
if (!processingEntity.isAlive() || !processingEntity.getBoundingBox()
.intersects(new AxisAlignedBB(pos).grow(.5f))) {
clear();
return;
}
@ -136,7 +144,7 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
if (!(processingEntity instanceof ItemEntity)) {
processingEntity.attackEntityFrom(CrushingWheelTileEntity.damageSource,
AllConfigs.SERVER.kinetics.crushingDamage.get());
AllConfigs.SERVER.kinetics.crushingDamage.get());
if (!processingEntity.isAlive()) {
processingEntity.setPosition(outPos.x, outPos.y - .75f, outPos.z);
}
@ -147,7 +155,8 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
itemEntity.setPickupDelay(20);
if (processingEntity.getY() < pos.getY() + .25f) {
inventory.clear();
inventory.setStackInSlot(0, itemEntity.getItem().copy());
inventory.setStackInSlot(0, itemEntity.getItem()
.copy());
itemInserted(inventory.getStackInSlot(0));
itemEntity.remove();
world.notifyBlockUpdate(pos, getBlockState(), getBlockState(), 2 | 16);
@ -161,15 +170,15 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
IParticleData particleData = null;
if (stack.getItem() instanceof BlockItem)
particleData =
new BlockParticleData(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock().getDefaultState());
particleData = new BlockParticleData(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock()
.getDefaultState());
else
particleData = new ItemParticleData(ParticleTypes.ITEM, stack);
Random r = world.rand;
for (int i = 0; i < 4; i++)
world.addParticle(particleData, pos.getX() + r.nextFloat(), pos.getY() + r.nextFloat(),
pos.getZ() + r.nextFloat(), 0, 0, 0);
pos.getZ() + r.nextFloat(), 0, 0, 0);
}
private void applyRecipe() {
@ -177,10 +186,12 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
List<ItemStack> list = new ArrayList<>();
if (recipe.isPresent()) {
int rolls = inventory.getStackInSlot(0).getCount();
int rolls = inventory.getStackInSlot(0)
.getCount();
inventory.clear();
for (int roll = 0; roll < rolls; roll++) {
List<ItemStack> rolledResults = recipe.get().rollResults();
List<ItemStack> rolledResults = recipe.get()
.rollResults();
for (int i = 0; i < rolledResults.size(); i++) {
ItemStack stack = rolledResults.get(i);
ItemHelper.addToList(stack, list);
@ -195,10 +206,11 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
}
public Optional<ProcessingRecipe<RecipeWrapper>> findRecipe() {
Optional<ProcessingRecipe<RecipeWrapper>> crushingRecipe =
world.getRecipeManager().getRecipe(AllRecipeTypes.CRUSHING.getType(), wrapper, world);
Optional<ProcessingRecipe<RecipeWrapper>> crushingRecipe = world.getRecipeManager()
.getRecipe(AllRecipeTypes.CRUSHING.getType(), wrapper, world);
if (!crushingRecipe.isPresent())
crushingRecipe = world.getRecipeManager().getRecipe(AllRecipeTypes.MILLING.getType(), wrapper, world);
crushingRecipe = world.getRecipeManager()
.getRecipe(AllRecipeTypes.MILLING.getType(), wrapper, world);
return crushingRecipe;
}
@ -231,7 +243,8 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
private void itemInserted(ItemStack stack) {
Optional<ProcessingRecipe<RecipeWrapper>> recipe = findRecipe();
inventory.remainingTime = recipe.isPresent() ? recipe.get().getProcessingDuration() : 100;
inventory.remainingTime = recipe.isPresent() ? recipe.get()
.getProcessingDuration() : 100;
inventory.appliedRecipe = false;
}

View file

@ -0,0 +1,59 @@
package com.simibubi.create.content.contraptions.components.press;
import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.HOLD;
import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.PASS;
import java.util.List;
import java.util.Optional;
import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity.Mode;
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult;
import net.minecraft.item.ItemStack;
public class BeltPressingCallbacks {
static ProcessingResult onItemReceived(TransportedItemStack transported, BeltInventory beltInventory,
MechanicalPressTileEntity press) {
if (press.getSpeed() == 0 || press.running)
return PASS;
if (!press.getRecipe(transported.stack)
.isPresent())
return PASS;
press.start(Mode.BELT);
return HOLD;
}
static ProcessingResult whenItemHeld(TransportedItemStack transportedStack, BeltInventory beltInventory,
MechanicalPressTileEntity pressTe) {
if (pressTe.getSpeed() == 0)
return PASS;
if (!pressTe.running)
return PASS;
if (pressTe.runningTicks != 30)
return HOLD;
Optional<PressingRecipe> recipe = pressTe.getRecipe(transportedStack.stack);
pressTe.pressedItems.clear();
pressTe.pressedItems.add(transportedStack.stack);
if (!recipe.isPresent())
return PASS;
ItemStack out = recipe.get()
.getRecipeOutput()
.copy();
List<ItemStack> multipliedOutput = ItemHelper.multipliedOutput(transportedStack.stack, out);
if (multipliedOutput.isEmpty())
transportedStack.stack = ItemStack.EMPTY;
transportedStack.stack = multipliedOutput.get(0);
pressTe.sendData();
return HOLD;
}
}

View file

@ -1,28 +1,16 @@
package com.simibubi.create.content.contraptions.components.press;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity.Mode;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.item.ItemHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
@ -30,12 +18,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class MechanicalPressBlock extends HorizontalKineticBlock
implements ITE<MechanicalPressTileEntity>, IBeltAttachment {
implements ITE<MechanicalPressTileEntity> {
public MechanicalPressBlock(Properties properties) {
super(properties);
@ -93,95 +80,6 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
return face.getAxis() == state.get(HORIZONTAL_FACING).getAxis();
}
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
onAttachmentPlaced(worldIn, pos, state);
}
@Override
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
return Arrays.asList(pos.up(2));
}
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
onAttachmentRemoved(worldIn, pos, state);
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
worldIn.removeTileEntity(pos);
}
}
@Override
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
return pos.down(2);
}
@Override
public boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos,
BlockState attachmentState, BlockState beltState) {
return AllBlocks.BELT.has(beltState) && beltState.get(BeltBlock.SLOPE) == Slope.HORIZONTAL;
}
@Override
public boolean startProcessingItem(BeltTileEntity belt, TransportedItemStack transported,
BeltAttachmentState state) {
try {
MechanicalPressTileEntity pressTe = getTileEntity(belt.getWorld(), state.attachmentPos);
if (pressTe.getSpeed() == 0)
return false;
if (pressTe.running)
return false;
if (!pressTe.getRecipe(transported.stack).isPresent())
return false;
state.processingDuration = 1;
pressTe.start(Mode.BELT);
return true;
} catch (TileEntityException e) {}
return false;
}
@Override
public boolean processItem(BeltTileEntity belt, TransportedItemStack transportedStack, BeltAttachmentState state) {
try {
MechanicalPressTileEntity pressTe = getTileEntity(belt.getWorld(), state.attachmentPos);
// Not powered
if (pressTe.getSpeed() == 0)
return false;
// Running
if (!pressTe.running)
return false;
if (pressTe.runningTicks != 30)
return true;
Optional<PressingRecipe> recipe = pressTe.getRecipe(transportedStack.stack);
pressTe.pressedItems.clear();
pressTe.pressedItems.add(transportedStack.stack);
if (!recipe.isPresent())
return false;
ItemStack out = recipe.get().getRecipeOutput().copy();
List<ItemStack> multipliedOutput = ItemHelper.multipliedOutput(transportedStack.stack, out);
if (multipliedOutput.isEmpty())
transportedStack.stack = ItemStack.EMPTY;
transportedStack.stack = multipliedOutput.get(0);
BeltTileEntity controllerTE = belt.getControllerTE();
if (controllerTE != null)
controllerTE.sendData();
pressTe.sendData();
return true;
} catch (TileEntityException e) {}
return false;
}
@Override
public Class<MechanicalPressTileEntity> getTileEntityClass() {
return MechanicalPressTileEntity.class;

View file

@ -11,6 +11,8 @@ import com.simibubi.create.content.contraptions.processing.BasinTileEntity.Basin
import com.simibubi.create.content.logistics.InWorldProcessing;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.Entity;
@ -59,6 +61,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
}
private static PressingInv pressingInv = new PressingInv();
public BeltProcessingBehaviour processingBehaviour;
public int runningTicks;
public boolean running;
public Mode mode;
@ -69,6 +73,15 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
mode = Mode.WORLD;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
processingBehaviour =
new BeltProcessingBehaviour(this).whenItemEnters((s, i) -> BeltPressingCallbacks.onItemReceived(s, i, this))
.whileItemHeld((s, i) -> BeltPressingCallbacks.whenItemHeld(s, i, this));
behaviours.add(processingBehaviour);
}
@Override
public void read(CompoundNBT compound) {
running = compound.getBoolean("Running");
@ -105,7 +118,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
@Override
public AxisAlignedBB getRenderBoundingBox() {
return new AxisAlignedBB(pos).expand(0, -1.5, 0).expand(0, 1, 0);
return new AxisAlignedBB(pos).expand(0, -1.5, 0)
.expand(0, 1, 0);
}
public float getRenderedHeadOffset(float partialTicks) {
@ -116,7 +130,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
}
if (runningTicks >= 40) {
return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0,
mode.headOffset);
mode.headOffset);
}
}
return 0;
@ -180,7 +194,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
if (basinInv.isPresent() && orElse instanceof BasinInventory) {
BasinInventory inv = (BasinInventory) orElse;
for (int slot = 0; slot < inv.getInputHandler().getSlots(); slot++) {
for (int slot = 0; slot < inv.getInputHandler()
.getSlots(); slot++) {
ItemStack stackInSlot = inv.getStackInSlot(slot);
if (stackInSlot.isEmpty())
continue;
@ -194,9 +209,9 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
if (!world.isRemote) {
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ITEM_BREAK.get(), SoundCategory.BLOCKS,
.5f, 1f);
.5f, 1f);
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ACTIVATION.get(), SoundCategory.BLOCKS,
.125f, 1f);
.125f, 1f);
}
}
@ -229,12 +244,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
pressedItems.forEach(stack -> makeCompactingParticleEffect(VecHelper.getCenterOf(pos.down(2)), stack));
}
if (mode == Mode.BELT) {
pressedItems.forEach(
stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(2)).add(0, 8 / 16f, 0), stack));
pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(2))
.add(0, 8 / 16f, 0), stack));
}
if (mode == Mode.WORLD) {
pressedItems.forEach(
stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(1)).add(0, -1 / 4f, 0), stack));
pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(1))
.add(0, -1 / 4f, 0), stack));
}
pressedItems.clear();
@ -243,9 +258,10 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
public void makePressingParticleEffect(Vec3d pos, ItemStack stack) {
if (world.isRemote) {
for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f).mul(1, 0, 1);
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(1, 0, 1);
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x,
motion.y + .125f, motion.z);
motion.y + .125f, motion.z);
}
}
}
@ -253,23 +269,24 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) {
if (world.isRemote) {
for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f).mul(1, 0, 1);
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f)
.mul(1, 0, 1);
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x,
motion.y + .25f, motion.z);
motion.y + .25f, motion.z);
}
}
}
public Optional<PressingRecipe> getRecipe(ItemStack item) {
pressingInv.setInventorySlotContents(0, item);
Optional<PressingRecipe> recipe =
world.getRecipeManager().getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world);
Optional<PressingRecipe> recipe = world.getRecipeManager()
.getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world);
return recipe;
}
public static boolean canCompress(NonNullList<Ingredient> ingredients) {
return (ingredients.size() == 4 || ingredients.size() == 9)
&& ItemHelper.condenseIngredients(ingredients).size() == 1;
return (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.condenseIngredients(ingredients)
.size() == 1;
}
@Override
@ -283,7 +300,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
return false;
NonNullList<Ingredient> ingredients = recipe.getIngredients();
if (!ingredients.stream().allMatch(Ingredient::isSimple))
if (!ingredients.stream()
.allMatch(Ingredient::isSimple))
return false;
List<ItemStack> remaining = new ArrayList<>();

View file

@ -61,18 +61,25 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> {
if (te.getSpeed() < 0 ^ alongZ)
offset = 1 - offset;
ItemStack stack = te.inventory.getStackInSlot(0);
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
IBakedModel modelWithOverrides = itemRenderer.getItemModelWithOverrides(stack, te.getWorld(), null);
boolean blockItem = modelWithOverrides.isGui3d();
ms.translate(alongZ ? offset : .5, blockItem ? .925f : 13f / 16f, alongZ ? .5 : offset);
ms.scale(.5f, .5f, .5f);
if (alongZ)
ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(90));
ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(90));
itemRenderer.renderItem(stack, ItemCameraTransforms.TransformType.FIXED, light, overlay, ms, buffer);
for (int i = 0; i < te.inventory.getSlots(); i++) {
ItemStack stack = te.inventory.getStackInSlot(i);
if (stack.isEmpty())
continue;
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
IBakedModel modelWithOverrides = itemRenderer.getItemModelWithOverrides(stack, te.getWorld(), null);
boolean blockItem = modelWithOverrides.isGui3d();
ms.translate(alongZ ? offset : .5, blockItem ? .925f : 13f / 16f, alongZ ? .5 : offset);
ms.scale(.5f, .5f, .5f);
if (alongZ)
ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(90));
ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(90));
itemRenderer.renderItem(stack, ItemCameraTransforms.TransformType.FIXED, light, overlay, ms, buffer);
break;
}
ms.pop();
}
}

View file

@ -8,13 +8,12 @@ import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity;
import com.simibubi.create.content.contraptions.processing.ProcessingInventory;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
@ -44,7 +43,6 @@ import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tags.BlockTags;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
@ -78,6 +76,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
super.addBehaviours(behaviours);
filtering = new FilteringBehaviour(this, new SawFilterSlot());
behaviours.add(filtering);
behaviours.add(new DirectBeltInputBehaviour(this));
}
@Override
@ -142,81 +141,51 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
Vec3d itemMovement = getItemMovementVec();
Direction itemMovementFacing = Direction.getFacingFromVector(itemMovement.x, itemMovement.y, itemMovement.z);
Vec3d outPos = VecHelper.getCenterOf(pos).add(itemMovement.scale(.5f).add(0, .5, 0));
Vec3d outMotion = itemMovement.scale(.0625).add(0, .125, 0);
if (inventory.remainingTime > 0)
return;
inventory.remainingTime = 0;
if (inventory.remainingTime <= 0) {
// Try moving items onto the belt
BlockPos nextPos = pos.add(itemMovement.x, itemMovement.y, itemMovement.z);
if (AllBlocks.BELT.has(world.getBlockState(nextPos))) {
TileEntity te = world.getTileEntity(nextPos);
if (te != null && te instanceof BeltTileEntity) {
for (int slot = 0; slot < inventory.getSlots(); slot++) {
ItemStack stack = inventory.getStackInSlot(slot);
if (stack.isEmpty())
continue;
if (((BeltTileEntity) te).tryInsertingFromSide(itemMovementFacing, stack, false))
inventory.setStackInSlot(slot, ItemStack.EMPTY);
else {
inventory.remainingTime = 0;
return;
}
}
inventory.clear();
inventory.remainingTime = -1;
sendData();
}
}
// Try moving items onto next saw
if (AllBlocks.MECHANICAL_SAW.has(world.getBlockState(nextPos))) {
TileEntity te = world.getTileEntity(nextPos);
if (te != null && te instanceof SawTileEntity) {
SawTileEntity sawTileEntity = (SawTileEntity) te;
Vec3d otherMovement = sawTileEntity.getItemMovementVec();
if (Direction.getFacingFromVector(otherMovement.x, otherMovement.y,
otherMovement.z) != itemMovementFacing.getOpposite()) {
for (int slot = 0; slot < inventory.getSlots(); slot++) {
ItemStack stack = inventory.getStackInSlot(slot);
if (stack.isEmpty())
continue;
ProcessingInventory sawInv = sawTileEntity.inventory;
if (sawInv.isEmpty()) {
sawInv.insertItem(0, stack, false);
inventory.setStackInSlot(slot, ItemStack.EMPTY);
} else {
inventory.remainingTime = 0;
return;
}
}
inventory.clear();
inventory.remainingTime = -1;
sendData();
}
}
}
// Eject Items
BlockPos nextPos = pos.add(itemMovement.x, itemMovement.y, itemMovement.z);
DirectBeltInputBehaviour behaviour = TileEntityBehaviour.get(world, nextPos, DirectBeltInputBehaviour.TYPE);
if (behaviour != null) {
boolean changed = false;
if (!behaviour.canInsertFromSide(itemMovementFacing))
return;
for (int slot = 0; slot < inventory.getSlots(); slot++) {
ItemStack stack = inventory.getStackInSlot(slot);
if (stack.isEmpty())
continue;
ItemEntity entityIn = new ItemEntity(world, outPos.x, outPos.y, outPos.z, stack);
entityIn.setMotion(outMotion);
world.addEntity(entityIn);
ItemStack remainder = behaviour.handleInsertion(stack, itemMovementFacing, false);
if (remainder.equals(stack, false))
continue;
inventory.setStackInSlot(slot, remainder);
changed = true;
}
if (changed) {
markDirty();
sendData();
}
inventory.clear();
world.updateComparatorOutputLevel(pos, getBlockState().getBlock());
inventory.remainingTime = -1;
sendData();
return;
}
return;
// Eject Items
Vec3d outPos = VecHelper.getCenterOf(pos)
.add(itemMovement.scale(.5f)
.add(0, .5, 0));
Vec3d outMotion = itemMovement.scale(.0625)
.add(0, .125, 0);
for (int slot = 0; slot < inventory.getSlots(); slot++) {
ItemStack stack = inventory.getStackInSlot(slot);
if (stack.isEmpty())
continue;
ItemEntity entityIn = new ItemEntity(world, outPos.x, outPos.y, outPos.z, stack);
entityIn.setMotion(outMotion);
world.addEntity(entityIn);
}
inventory.clear();
world.updateComparatorOutputLevel(pos, getBlockState().getBlock());
inventory.remainingTime = -1;
sendData();
}
@Override
@ -240,8 +209,8 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
IParticleData particleData = null;
float speed = 1;
if (stack.getItem() instanceof BlockItem)
particleData =
new BlockParticleData(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock().getDefaultState());
particleData = new BlockParticleData(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock()
.getDefaultState());
else {
particleData = new ItemParticleData(ParticleTypes.ITEM, stack);
speed = .125f;
@ -253,7 +222,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
float offset = inventory.recipeDuration != 0 ? (float) (inventory.remainingTime) / inventory.recipeDuration : 0;
offset -= .5f;
world.addParticle(particleData, pos.getX() + -vec.x * offset, pos.getY() + .45f, pos.getZ() + -vec.z * offset,
-vec.x * speed, r.nextFloat() * speed, -vec.z * speed);
-vec.x * speed, r.nextFloat() * speed, -vec.z * speed);
}
public Vec3d getItemMovementVec() {
@ -271,7 +240,8 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
IRecipe<?> recipe = recipes.get(recipeIndex);
int rolls = inventory.getStackInSlot(0).getCount();
int rolls = inventory.getStackInSlot(0)
.getCount();
inventory.clear();
List<ItemStack> list = new ArrayList<>();
@ -280,7 +250,8 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
if (recipe instanceof CuttingRecipe)
results = ((CuttingRecipe) recipe).rollResults();
else if (recipe instanceof StonecuttingRecipe)
results.add(recipe.getRecipeOutput().copy());
results.add(recipe.getRecipeOutput()
.copy());
for (int i = 0; i < results.size(); i++) {
ItemStack stack = results.get(i);
@ -294,10 +265,11 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
private List<? extends IRecipe<?>> getRecipes() {
List<IRecipe<?>> startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType()));
return startedSearch.stream().filter(RecipeConditions.outputMatchesFilter(filtering))
.filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0)))
.collect(Collectors.toList());
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType()));
return startedSearch.stream()
.filter(RecipeConditions.outputMatchesFilter(filtering))
.filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0)))
.collect(Collectors.toList());
}
public void insertItem(ItemEntity entity) {
@ -309,7 +281,8 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
return;
inventory.clear();
inventory.insertItem(0, entity.getItem().copy(), false);
inventory.insertItem(0, entity.getItem()
.copy(), false);
entity.remove();
}
@ -357,7 +330,9 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
@Override
protected boolean shouldRun() {
return getBlockState().get(SawBlock.FACING).getAxis().isHorizontal();
return getBlockState().get(SawBlock.FACING)
.getAxis()
.isHorizontal();
}
@Override

View file

@ -1,8 +1,11 @@
package com.simibubi.create.content.contraptions.processing;
import java.util.List;
import java.util.Optional;
import com.simibubi.create.foundation.tileEntity.SyncedTileEntity;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
@ -19,7 +22,7 @@ import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.items.wrapper.RecipeWrapper;
public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEntity {
public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity {
public boolean contentsChanged;
@ -96,7 +99,12 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
contentsChanged = true;
recipeInventory = new BasinInputInventory();
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this));
}
@Override
public void read(CompoundNBT compound) {
super.read(compound);

View file

@ -1,202 +0,0 @@
package com.simibubi.create.content.contraptions.relays.belt;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
public enum AllBeltAttachments { //TODO rework this nonsense
BELT_FUNNEL(AllBlocks.FUNNEL.get()),
BELT_OBSERVER(AllBlocks.BELT_OBSERVER.get()),
MECHANICAL_PRESS(AllBlocks.MECHANICAL_PRESS.get()),
LOGISTICAL_ATTACHABLES(AllBlocks.EXTRACTOR.get()),
;
IBeltAttachment attachment;
private AllBeltAttachments(Block attachment) {
this.attachment = (IBeltAttachment) attachment;
}
public interface IBeltAttachment {
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState);
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state);
default boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos,
BlockState attachmentState, BlockState beltState) {
return true;
}
default boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
return false;
}
default boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported,
BeltAttachmentState state) {
return false;
}
default boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
return false;
}
default void onAttachmentPlaced(IWorld world, BlockPos pos, BlockState state) {
BlockPos beltPos = getBeltPositionForAttachment(world, pos, state);
BeltTileEntity belt = BeltHelper.getSegmentTE(world, beltPos);
if (belt == null)
return;
if (!isAttachedCorrectly(world, pos, beltPos, state, world.getBlockState(beltPos)))
return;
belt.attachmentTracker.addAttachment(world, pos);
belt.markDirty();
belt.sendData();
}
default void onAttachmentRemoved(IWorld world, BlockPos pos, BlockState state) {
BlockPos beltPos = getBeltPositionForAttachment(world, pos, state);
BeltTileEntity belt = BeltHelper.getSegmentTE(world, beltPos);
if (belt == null)
return;
if (!isAttachedCorrectly(world, pos, beltPos, state, world.getBlockState(beltPos)))
return;
belt.attachmentTracker.removeAttachment(pos);
belt.markDirty();
belt.sendData();
}
}
public static class BeltAttachmentState {
public IBeltAttachment attachment;
public BlockPos attachmentPos;
public int processingDuration;
public Entity processingEntity;
public TransportedItemStack processingStack;
public BeltAttachmentState(IBeltAttachment attachment, BlockPos attachmentPos) {
this.attachment = attachment;
this.attachmentPos = attachmentPos;
}
}
public static class Tracker {
public List<BeltAttachmentState> attachments;
private BeltTileEntity te;
public Tracker(BeltTileEntity te) {
attachments = new LinkedList<>();
this.te = te;
}
public void findAttachments(BeltTileEntity belt) {
for (AllBeltAttachments ba : AllBeltAttachments.values()) {
World world = belt.getWorld();
BlockPos beltPos = belt.getPos();
BlockState beltState = belt.getBlockState();
List<BlockPos> attachmentPositions =
ba.attachment.getPotentialAttachmentPositions(world, beltPos, beltState);
for (BlockPos potentialPos : attachmentPositions) {
if (!world.isBlockPresent(potentialPos))
continue;
BlockState state = world.getBlockState(potentialPos);
if (!(state.getBlock() instanceof IBeltAttachment))
continue;
IBeltAttachment attachment = (IBeltAttachment) state.getBlock();
if (!attachment.getBeltPositionForAttachment(world, potentialPos, state).equals(beltPos))
continue;
if (!attachment.isAttachedCorrectly(world, potentialPos, beltPos, state, beltState))
continue;
addAttachment(world, potentialPos);
}
}
}
public BeltAttachmentState addAttachment(IWorld world, BlockPos pos) {
BlockState state = world.getBlockState(pos);
removeAttachment(pos);
if (!(state.getBlock() instanceof IBeltAttachment)) {
Create.logger.warn("Missing belt attachment for Belt at " + pos.toString());
return null;
}
BeltAttachmentState newAttachmentState = new BeltAttachmentState((IBeltAttachment) state.getBlock(), pos);
attachments.add(newAttachmentState);
te.markDirty();
return newAttachmentState;
}
public void removeAttachment(BlockPos pos) {
BeltAttachmentState toRemove = null;
for (BeltAttachmentState atState : attachments)
if (atState.attachmentPos.equals(pos))
toRemove = atState;
if (toRemove != null)
attachments.remove(toRemove);
te.markDirty();
}
public void forEachAttachment(Consumer<BeltAttachmentState> consumer) {
attachments.forEach(consumer::accept);
}
public void readAndSearch(CompoundNBT nbt, BeltTileEntity belt) {
attachments.clear();
if (!nbt.contains("HasAttachments")) {
findAttachments(belt);
return;
}
if (nbt.contains("AttachmentData")) {
ListNBT list = (ListNBT) nbt.get("AttachmentData");
for (INBT data : list) {
CompoundNBT stateNBT = (CompoundNBT) data;
BlockPos attachmentPos = NBTUtil.readBlockPos(stateNBT.getCompound("Position"));
BeltAttachmentState atState = addAttachment(belt.getWorld(), attachmentPos);
if (atState == null)
continue;
atState.processingDuration = stateNBT.getInt("Duration");
}
}
}
public void write(CompoundNBT nbt) {
if (!attachments.isEmpty()) {
nbt.putBoolean("HasAttachments", true);
ListNBT list = new ListNBT();
forEachAttachment(atState -> {
CompoundNBT stateNBT = new CompoundNBT();
stateNBT.put("Position", NBTUtil.writeBlockPos(atState.attachmentPos));
stateNBT.putInt("Duration", atState.processingDuration);
list.add(stateNBT);
});
nbt.put("AttachmentData", list);
}
}
}
}

View file

@ -210,9 +210,6 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
updateNeighbouringTunnel(worldIn, pos, state);
withTileEntityDo(worldIn, pos, te -> {
te.attachmentTracker.findAttachments(te);
});
}
@Override

View file

@ -109,7 +109,7 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> {
int verticality = slope == Slope.DOWNWARD ? -1 : slope == Slope.UPWARD ? 1 : 0;
boolean slopeAlongX = te.getBeltFacing().getAxis() == Axis.X;
for (TransportedItemStack transported : te.getInventory().getItems()) {
for (TransportedItemStack transported : te.getInventory().getTransportedItems()) {
ms.push();
MatrixStacker.of(ms).nudge(transported.angle);
float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition);

View file

@ -15,13 +15,15 @@ import java.util.Map;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.Tracker;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Part;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory;
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler;
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo;
import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.utility.ColorHelper;
import net.minecraft.block.BlockState;
@ -46,7 +48,6 @@ import net.minecraftforge.items.IItemHandler;
public class BeltTileEntity extends KineticTileEntity {
public Map<Entity, TransportedEntityInfo> passengers;
public AllBeltAttachments.Tracker attachmentTracker;
public int color;
public int beltLength;
public int index;
@ -61,11 +62,18 @@ public class BeltTileEntity extends KineticTileEntity {
public BeltTileEntity(TileEntityType<? extends BeltTileEntity> type) {
super(type);
controller = BlockPos.ZERO;
attachmentTracker = new Tracker(this);
itemHandler = LazyOptional.empty();
color = -1;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
behaviours.add(new DirectBeltInputBehaviour(this)
.onlyInsertWhen(d -> getSpeed() != 0 && getMovementFacing() != d.getOpposite())
.setInsertionHandler(this::tryInsertingFromSide));
}
@Override
public void tick() {
super.tick();
@ -75,12 +83,6 @@ public class BeltTileEntity extends KineticTileEntity {
BeltBlock.initBelt(world, pos);
if (!AllBlocks.BELT.has(world.getBlockState(pos)))
return;
// Initialize Belt Attachments
if (world != null && trackerUpdateTag != null) {
attachmentTracker.readAndSearch(trackerUpdateTag, this);
trackerUpdateTag = null;
}
if (getSpeed() == 0)
return;
@ -136,7 +138,7 @@ public class BeltTileEntity extends KineticTileEntity {
BeltInventory inventory = ((BeltTileEntity) te).getInventory();
if (inventory == null)
return;
IItemHandler handler = inventory.createHandlerForSegment(index);
IItemHandler handler = new ItemHandlerBeltSegment(inventory, index);
itemHandler = LazyOptional.of(() -> handler);
}
@ -163,8 +165,6 @@ public class BeltTileEntity extends KineticTileEntity {
@Override
public CompoundNBT write(CompoundNBT compound) {
attachmentTracker.write(compound);
if (controller != null)
compound.put("Controller", NBTUtil.writeBlockPos(controller));
compound.putBoolean("IsController", isController());
@ -246,7 +246,8 @@ public class BeltTileEntity extends KineticTileEntity {
}
public float getDirectionAwareBeltMovementSpeed() {
int offset = getBeltFacing().getAxisDirection().getOffset();
int offset = getBeltFacing().getAxisDirection()
.getOffset();
if (getBeltFacing().getAxis() == Axis.X)
offset *= -1;
return getBeltMovementSpeed() * offset;
@ -270,8 +271,8 @@ public class BeltTileEntity extends KineticTileEntity {
if (part == MIDDLE)
return false;
boolean movingPositively =
(getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1)) ^ direction.getAxis() == Axis.X;
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection()
.getOffset() == 1)) ^ direction.getAxis() == Axis.X;
return part == Part.START ^ movingPositively;
}
@ -311,8 +312,8 @@ public class BeltTileEntity extends KineticTileEntity {
public Direction getMovementFacing() {
Axis axis = getBeltFacing().getAxis();
return Direction
.getFacingFromAxisDirection(axis, getBeltMovementSpeed() < 0 ^ axis == Axis.X ? NEGATIVE : POSITIVE);
return Direction.getFacingFromAxisDirection(axis,
getBeltMovementSpeed() < 0 ^ axis == Axis.X ? NEGATIVE : POSITIVE);
}
protected Direction getBeltFacing() {
@ -332,29 +333,39 @@ public class BeltTileEntity extends KineticTileEntity {
return inventory;
}
/**
* always target a DirectBeltInsertionBehaviour
*/
@Deprecated
public boolean tryInsertingFromSide(Direction side, ItemStack stack, boolean simulate) {
return tryInsertingFromSide(side, new TransportedItemStack(stack), simulate);
return tryInsertingFromSide(new TransportedItemStack(stack), side, simulate).isEmpty();
}
public boolean tryInsertingFromSide(Direction side, TransportedItemStack transportedStack, boolean simulate) {
private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) {
BeltTileEntity nextBeltController = getControllerTE();
ItemStack inserted = transportedStack.stack;
ItemStack empty = ItemStack.EMPTY;
if (nextBeltController == null)
return false;
return inserted;
BeltInventory nextInventory = nextBeltController.getInventory();
if (getSpeed() == 0)
return false;
if (!nextInventory.canInsertFrom(index, side))
return false;
return inserted;
if (!nextInventory.canInsertAtFromSide(index, side))
return inserted;
if (simulate)
return true;
return empty;
transportedStack = transportedStack.copy();
transportedStack.beltPosition = index + .5f - Math.signum(getDirectionAwareBeltMovementSpeed()) / 16f;
Direction movementFacing = getMovementFacing();
if (!side.getAxis().isVertical()) {
if (!side.getAxis()
.isVertical()) {
if (movementFacing != side) {
transportedStack.sideOffset = side.getAxisDirection().getOffset() * .35f;
transportedStack.sideOffset = side.getAxisDirection()
.getOffset() * .35f;
if (side.getAxis() == Axis.X)
transportedStack.sideOffset *= -1;
} else
@ -368,8 +379,7 @@ public class BeltTileEntity extends KineticTileEntity {
nextInventory.addItem(transportedStack);
nextBeltController.markDirty();
nextBeltController.sendData();
return true;
return empty;
}
}

View file

@ -1,5 +1,7 @@
package com.simibubi.create.content.contraptions.relays.belt.transport;
import static com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler.flapTunnel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@ -8,32 +10,26 @@ import java.util.List;
import java.util.function.Function;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
public class BeltInventory {
@ -52,9 +48,9 @@ public class BeltInventory {
public void tick() {
// Reverse item collection if belt just reversed
if (beltMovementPositive != movingPositive()) {
beltMovementPositive = movingPositive();
Collections.reverse(getItems());
if (beltMovementPositive != belt.getDirectionAwareBeltMovementSpeed() > 0) {
beltMovementPositive = !beltMovementPositive;
Collections.reverse(items);
belt.markDirty();
belt.sendData();
}
@ -69,23 +65,31 @@ public class BeltInventory {
// Assuming the first entry is furthest on the belt
TransportedItemStack stackInFront = null;
TransportedItemStack current = null;
Iterator<TransportedItemStack> iterator = getItems().iterator();
TransportedItemStack currentItem = null;
Iterator<TransportedItemStack> iterator = items.iterator();
// Useful stuff
float beltSpeed = belt.getDirectionAwareBeltMovementSpeed();
Direction movementFacing = belt.getMovementFacing();
boolean horizontal = belt.getBlockState()
.get(BeltBlock.SLOPE) == Slope.HORIZONTAL;
float spacing = 1;
boolean onClient = belt.getWorld().isRemote;
World world = belt.getWorld();
boolean onClient = world.isRemote;
Items: while (iterator.hasNext()) {
stackInFront = current;
current = iterator.next();
current.prevBeltPosition = current.beltPosition;
current.prevSideOffset = current.sideOffset;
// resolve ending only when items will reach it this tick
Ending ending = Ending.UNRESOLVED;
if (current.stack.isEmpty()) {
// Loop over items
while (iterator.hasNext()) {
stackInFront = currentItem;
currentItem = iterator.next();
currentItem.prevBeltPosition = currentItem.beltPosition;
currentItem.prevSideOffset = currentItem.sideOffset;
if (currentItem.stack.isEmpty()) {
iterator.remove();
current = null;
currentItem = null;
continue;
}
@ -93,12 +97,12 @@ public class BeltInventory {
if (onClient)
movement *= ServerSpeedProvider.get();
// Don't move if locked
if (onClient && current.locked)
// Don't move if held by processing (client)
if (onClient && currentItem.locked)
continue;
// Don't move if other items are waiting in front
float currentPos = current.beltPosition;
float currentPos = currentItem.beltPosition;
if (stackInFront != null) {
float diff = stackInFront.beltPosition - currentPos;
if (Math.abs(diff) <= spacing)
@ -107,236 +111,182 @@ public class BeltInventory {
beltMovementPositive ? Math.min(movement, diff - spacing) : Math.max(movement, diff + spacing);
}
// Determine current segment
int segmentBefore = (int) currentPos;
float min = segmentBefore + .5f - (SEGMENT_WINDOW / 2);
float max = segmentBefore + .5f + (SEGMENT_WINDOW / 2);
if (currentPos < min || currentPos > max)
segmentBefore = -1;
// Don't move beyond the edge
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
if (Math.abs(diffToEnd) < Math.abs(movement) + 1) {
if (ending == Ending.UNRESOLVED)
ending = resolveEnding();
diffToEnd += beltMovementPositive ? -ending.margin : ending.margin;
}
float limitedMovement =
beltMovementPositive ? Math.min(movement, diffToEnd) : Math.max(movement, diffToEnd);
float nextOffset = current.beltPosition + limitedMovement;
float nextOffset = currentItem.beltPosition + limitedMovement;
if (!onClient && segmentBefore != -1) {
// Don't move if belt attachments want to continue processing
if (current.locked) {
BeltTileEntity beltSegment = BeltHelper.getBeltAtSegment(belt, segmentBefore);
if (beltSegment != null) {
// wait in case belt isnt initialized yet
if (current.locked && beltSegment.trackerUpdateTag != null)
continue;
current.locked = false;
List<BeltAttachmentState> attachments = beltSegment.attachmentTracker.attachments;
for (BeltAttachmentState attachmentState : attachments) {
if (attachmentState.attachment.processItem(beltSegment, current, attachmentState))
current.locked = true;
}
if (!current.locked || current.stack.isEmpty()) {
if (!attachments.isEmpty())
attachments.add(attachments.remove(0));
belt.sendData();
}
continue;
}
}
// See if any new belt processing catches the item
if (current.beltPosition > .5f || beltMovementPositive) {
int firstUpcomingSegment = (int) (current.beltPosition + (beltMovementPositive ? .5f : -.5f));
for (int segment = firstUpcomingSegment; beltMovementPositive ? segment + .5f <= nextOffset
: segment + .5f >= nextOffset; segment += beltMovementPositive ? 1 : -1) {
BeltTileEntity beltSegment = BeltHelper.getBeltAtSegment(belt, segment);
if (beltSegment == null)
break;
for (BeltAttachmentState attachmentState : beltSegment.attachmentTracker.attachments) {
ItemStack stackBefore = current.stack.copy();
if (attachmentState.attachment.startProcessingItem(beltSegment, current, attachmentState)) {
current.beltPosition = segment + .5f + (beltMovementPositive ? 1 / 64f : -1 / 64f);
current.locked = true;
belt.sendData();
continue Items;
}
if (!stackBefore.equals(current.stack, true))
belt.sendData();
}
}
// Belt item processing
if (!onClient && horizontal) {
ItemStack item = currentItem.stack;
if (handleBeltProcessingAndCheckIfRemoved(currentItem, nextOffset)) {
iterator.remove();
belt.sendData();
continue;
}
if (item != currentItem.stack)
belt.sendData();
if (currentItem.locked)
continue;
}
// Belt tunnels
{
int seg1 = (int) current.beltPosition;
int seg2 = (int) nextOffset;
if (!beltMovementPositive && nextOffset == 0)
seg2 = -1;
if (seg1 != seg2) {
if (stuckAtTunnel(seg2, current.stack, movementFacing)) {
continue;
}
if (!onClient) {
flapTunnel(seg1, movementFacing, false);
flapTunnel(seg2, movementFacing.getOpposite(), true);
}
}
}
// Belt Tunnels
BeltTunnelInteractionHandler.flapTunnelsAndCheckIfStuck(this, currentItem, nextOffset);
// Apply Movement
current.beltPosition += limitedMovement;
current.sideOffset += (current.getTargetSideOffset() - current.sideOffset) * Math.abs(limitedMovement) * 2f;
currentPos = current.beltPosition;
currentItem.beltPosition += limitedMovement;
currentItem.sideOffset +=
(currentItem.getTargetSideOffset() - currentItem.sideOffset) * Math.abs(limitedMovement) * 2f;
currentPos = currentItem.beltPosition;
// Determine segment after movement
int segmentAfter = (int) currentPos;
min = segmentAfter + .5f - (SEGMENT_WINDOW / 2);
max = segmentAfter + .5f + (SEGMENT_WINDOW / 2);
if (currentPos < min || currentPos > max)
segmentAfter = -1;
// Item changed segments
World world = belt.getWorld();
if (segmentBefore != segmentAfter) {
for (int segment : new int[] { segmentBefore, segmentAfter }) {
if (segment == -1)
continue;
if (!world.isRemote)
world
.updateComparatorOutputLevel(BeltHelper.getPositionForOffset(belt, segment),
belt.getBlockState().getBlock());
}
}
// Movement successful
if (limitedMovement == movement || onClient)
continue;
// End reached
if (limitedMovement != movement) {
if (world.isRemote)
continue;
int lastOffset = beltMovementPositive ? belt.beltLength - 1 : 0;
BlockPos nextPosition =
BeltHelper.getPositionForOffset(belt, beltMovementPositive ? belt.beltLength : -1);
BlockState state = world.getBlockState(nextPosition);
// next block is a basin or a saw
if (AllBlocks.BASIN.has(state) || AllBlocks.MECHANICAL_SAW.has(state)
|| AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(state)) {
TileEntity te = world.getTileEntity(nextPosition);
if (te != null) {
LazyOptional<IItemHandler> optional =
te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
if (optional.isPresent()) {
IItemHandler itemHandler = optional.orElse(null);
ItemStack remainder =
ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(), false);
if (remainder.equals(current.stack, false))
continue;
current.stack = remainder;
if (remainder.isEmpty()) {
iterator.remove();
current = null;
flapTunnel(lastOffset, movementFacing, false);
}
belt.sendData();
}
}
continue;
}
// next block is not a belt
if (!AllBlocks.BELT.has(state) || state.get(BeltBlock.SLOPE) == Slope.VERTICAL) {
if (!Block.hasSolidSide(state, world, nextPosition, movementFacing.getOpposite())) {
eject(current);
iterator.remove();
current = null;
flapTunnel(lastOffset, movementFacing, false);
belt.sendData();
}
continue;
}
// Next block is a belt
TileEntity te = world.getTileEntity(nextPosition);
if (te == null || !(te instanceof BeltTileEntity))
continue;
BeltTileEntity nextBelt = (BeltTileEntity) te;
Direction nextMovementFacing = nextBelt.getMovementFacing();
// next belt goes the opposite way
if (nextMovementFacing == movementFacing.getOpposite())
continue;
// Inserting into other belt
if (nextBelt.tryInsertingFromSide(movementFacing, current, false)) {
iterator.remove();
current = null;
flapTunnel(lastOffset, movementFacing, false);
belt.sendData();
}
int lastOffset = beltMovementPositive ? belt.beltLength - 1 : 0;
BlockPos nextPosition = BeltHelper.getPositionForOffset(belt, beltMovementPositive ? belt.beltLength : -1);
if (ending == Ending.FUNNEL) {
// TODO
continue;
}
}
if (ending == Ending.INSERT) {
DirectBeltInputBehaviour inputBehaviour =
TileEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE);
if (inputBehaviour == null)
continue;
if (!inputBehaviour.canInsertFromSide(movementFacing))
continue;
ItemStack remainder = inputBehaviour.handleInsertion(currentItem, movementFacing, false);
if (remainder.equals(currentItem.stack, false))
continue;
currentItem.stack = remainder;
if (remainder.isEmpty())
iterator.remove();
flapTunnel(this, lastOffset, movementFacing, false);
belt.sendData();
continue;
}
if (ending == Ending.BLOCKED)
continue;
if (ending == Ending.EJECT) {
eject(currentItem);
iterator.remove();
flapTunnel(this, lastOffset, movementFacing, false);
belt.sendData();
continue;
}
}
}
private boolean stuckAtTunnel(int offset, ItemStack stack, Direction movementDirection) {
BlockPos pos = BeltHelper.getPositionForOffset(belt, offset).up();
if (!AllBlocks.BELT_TUNNEL.has(belt.getWorld().getBlockState(pos)))
return false;
TileEntity te = belt.getWorld().getTileEntity(pos);
if (te == null || !(te instanceof BeltTunnelTileEntity))
return false;
protected boolean handleBeltProcessingAndCheckIfRemoved(TransportedItemStack currentItem, float nextOffset) {
int currentSegment = (int) currentItem.beltPosition;
Direction flapFacing = movementDirection.getOpposite();
// Continue processing if held
if (currentItem.locked) {
BeltProcessingBehaviour processingBehaviour = getBeltProcessingAtSegment(currentSegment);
BeltTunnelTileEntity tunnel = (BeltTunnelTileEntity) te;
if (!tunnel.flaps.containsKey(flapFacing))
return false;
if (!tunnel.syncedFlaps.containsKey(flapFacing))
return false;
ItemStack heldItem = tunnel.syncedFlaps.get(flapFacing);
if (heldItem == null) {
tunnel.syncedFlaps.put(flapFacing, ItemStack.EMPTY);
if (processingBehaviour == null) {
currentItem.locked = false;
belt.sendData();
return false;
}
ProcessingResult result = processingBehaviour.handleHeldItem(currentItem, this);
if (result == ProcessingResult.REMOVE)
return true;
if (result == ProcessingResult.HOLD)
return false;
currentItem.locked = false;
belt.sendData();
return false;
}
if (heldItem == ItemStack.EMPTY) {
tunnel.syncedFlaps.put(flapFacing, stack);
return true;
// See if any new belt processing catches the item
if (currentItem.beltPosition > .5f || beltMovementPositive) {
int firstUpcomingSegment = (int) (currentItem.beltPosition + (beltMovementPositive ? .5f : -.5f));
int step = beltMovementPositive ? 1 : -1;
for (int segment = firstUpcomingSegment; beltMovementPositive ? segment + .5f <= nextOffset
: segment + .5f >= nextOffset; segment += step) {
BeltProcessingBehaviour processingBehaviour = getBeltProcessingAtSegment(segment);
if (processingBehaviour == null)
continue;
ProcessingResult result = processingBehaviour.handleReceivedItem(currentItem, this);
if (result == ProcessingResult.REMOVE)
return true;
if (result == ProcessingResult.HOLD) {
currentItem.beltPosition = segment + .5f + (beltMovementPositive ? 1 / 64f : -1 / 64f);
currentItem.locked = true;
belt.sendData();
return false;
}
}
}
List<BeltTunnelTileEntity> group = BeltTunnelBlock.getSynchronizedGroup(belt.getWorld(), pos, flapFacing);
for (BeltTunnelTileEntity otherTunnel : group)
if (otherTunnel.syncedFlaps.get(flapFacing) == ItemStack.EMPTY)
return true;
for (BeltTunnelTileEntity otherTunnel : group)
otherTunnel.syncedFlaps.put(flapFacing, null);
return true;
return false;
}
private void flapTunnel(int offset, Direction side, boolean inward) {
if (belt.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL)
return;
BlockPos pos = BeltHelper.getPositionForOffset(belt, offset).up();
if (!AllBlocks.BELT_TUNNEL.has(belt.getWorld().getBlockState(pos)))
return;
TileEntity te = belt.getWorld().getTileEntity(pos);
if (te == null || !(te instanceof BeltTunnelTileEntity))
return;
((BeltTunnelTileEntity) te).flap(side, inward ^ side.getAxis() == Axis.Z);
protected BeltProcessingBehaviour getBeltProcessingAtSegment(int segment) {
return TileEntityBehaviour.get(belt.getWorld(), BeltHelper.getPositionForOffset(belt, segment)
.up(2), BeltProcessingBehaviour.TYPE);
}
private enum Ending {
UNRESOLVED(0), EJECT(0), INSERT(.25f), FUNNEL(.35f), BLOCKED(.45f);
private float margin;
Ending(float f) {
this.margin = f;
}
}
private Ending resolveEnding() {
int lastOffset = beltMovementPositive ? belt.beltLength - 1 : 0;
World world = belt.getWorld();
BlockPos lastPosition = BeltHelper.getPositionForOffset(belt, lastOffset);
BlockPos nextPosition = BeltHelper.getPositionForOffset(belt, beltMovementPositive ? belt.beltLength : -1);
if (AllBlocks.BELT_FUNNEL.has(world.getBlockState(lastPosition.up())))
return Ending.FUNNEL;
DirectBeltInputBehaviour inputBehaviour =
TileEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE);
if (inputBehaviour != null)
return Ending.INSERT;
if (Block.hasSolidSide(world.getBlockState(nextPosition), world, nextPosition, belt.getMovementFacing()
.getOpposite()))
return Ending.BLOCKED;
return Ending.EJECT;
}
//
public boolean canInsertAt(int segment) {
return canInsertFrom(segment, Direction.UP);
return canInsertAtFromSide(segment, Direction.UP);
}
public boolean canInsertFrom(int segment, Direction side) {
public boolean canInsertAtFromSide(int segment, Direction side) {
float segmentPos = segment;
if (belt.getMovementFacing() == side.getOpposite())
return false;
@ -345,7 +295,7 @@ public class BeltInventory {
else if (!beltMovementPositive)
segmentPos += 1f;
for (TransportedItemStack stack : getItems())
for (TransportedItemStack stack : items)
if (isBlocking(segment, side, segmentPos, stack))
return false;
for (TransportedItemStack stack : toInsert)
@ -358,7 +308,7 @@ public class BeltInventory {
private boolean isBlocking(int segment, Direction side, float segmentPos, TransportedItemStack stack) {
float currentPos = stack.beltPosition;
if (stack.insertedAt == segment && stack.insertedFrom == side
&& (beltMovementPositive ? currentPos <= segmentPos + 1 : currentPos >= segmentPos - 1))
&& (beltMovementPositive ? currentPos <= segmentPos + 1 : currentPos >= segmentPos - 1))
return true;
return false;
}
@ -368,23 +318,23 @@ public class BeltInventory {
}
private void insert(TransportedItemStack newStack) {
if (getItems().isEmpty())
getItems().add(newStack);
if (items.isEmpty())
items.add(newStack);
else {
int index = 0;
for (TransportedItemStack stack : getItems()) {
for (TransportedItemStack stack : items) {
if (stack.compareTo(newStack) > 0 == beltMovementPositive)
break;
index++;
}
getItems().add(index, newStack);
items.add(index, newStack);
}
}
public TransportedItemStack getStackAtOffset(int offset) {
float min = offset + .5f - (SEGMENT_WINDOW / 2);
float max = offset + .5f + (SEGMENT_WINDOW / 2);
for (TransportedItemStack stack : getItems()) {
for (TransportedItemStack stack : items) {
if (stack.beltPosition > max)
continue;
if (stack.beltPosition > min)
@ -394,17 +344,16 @@ public class BeltInventory {
}
public void read(CompoundNBT nbt) {
getItems().clear();
nbt
.getList("Items", NBT.TAG_COMPOUND)
.forEach(inbt -> getItems().add(TransportedItemStack.read((CompoundNBT) inbt)));
items.clear();
nbt.getList("Items", NBT.TAG_COMPOUND)
.forEach(inbt -> items.add(TransportedItemStack.read((CompoundNBT) inbt)));
beltMovementPositive = nbt.getBoolean("PositiveOrder");
}
public CompoundNBT write() {
CompoundNBT nbt = new CompoundNBT();
ListNBT itemsNBT = new ListNBT();
getItems().forEach(stack -> itemsNBT.add(stack.serializeNBT()));
items.forEach(stack -> itemsNBT.add(stack.serializeNBT()));
nbt.put("Items", itemsNBT);
nbt.putBoolean("PositiveOrder", beltMovementPositive);
return nbt;
@ -414,33 +363,27 @@ public class BeltInventory {
ItemStack ejected = stack.stack;
Vec3d outPos = BeltHelper.getVectorForOffset(belt, stack.beltPosition);
float movementSpeed = Math.max(Math.abs(belt.getBeltMovementSpeed()), 1 / 8f);
Vec3d outMotion = new Vec3d(belt.getBeltChainDirection()).scale(movementSpeed).add(0, 1 / 8f, 0);
Vec3d outMotion = new Vec3d(belt.getBeltChainDirection()).scale(movementSpeed)
.add(0, 1 / 8f, 0);
outPos.add(outMotion.normalize());
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y + 6 / 16f, outPos.z, ejected);
entity.setMotion(outMotion);
entity.setDefaultPickupDelay();
entity.velocityChanged = true;
belt.getWorld().addEntity(entity);
belt.getWorld()
.addEntity(entity);
}
public void ejectAll() {
getItems().forEach(this::eject);
getItems().clear();
}
private boolean movingPositive() {
return belt.getDirectionAwareBeltMovementSpeed() > 0;
}
public IItemHandler createHandlerForSegment(int segment) {
return new ItemHandlerBeltSegment(this, segment);
items.forEach(this::eject);
items.clear();
}
public void forEachWithin(float position, float distance,
Function<TransportedItemStack, List<TransportedItemStack>> callback) {
Function<TransportedItemStack, List<TransportedItemStack>> callback) {
List<TransportedItemStack> toBeAdded = new ArrayList<>();
boolean dirty = false;
for (Iterator<TransportedItemStack> iterator = getItems().iterator(); iterator.hasNext();) {
for (Iterator<TransportedItemStack> iterator = items.iterator(); iterator.hasNext();) {
TransportedItemStack transportedItemStack = iterator.next();
if (Math.abs(position - transportedItemStack.beltPosition) < distance) {
List<TransportedItemStack> apply = callback.apply(transportedItemStack);
@ -458,7 +401,7 @@ public class BeltInventory {
}
}
public List<TransportedItemStack> getItems() {
public List<TransportedItemStack> getTransportedItems() {
return items;
}

View file

@ -8,7 +8,6 @@ import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Part;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
@ -99,16 +98,6 @@ public class BeltMovementHandler {
((LivingEntity) entityIn).addPotionEffect(new EffectInstance(Effects.SLOWNESS, 10, 1, false, false));
}
BeltTileEntity belt = (BeltTileEntity) te;
// Attachment pauses movement
for (BeltAttachmentState state : belt.attachmentTracker.attachments) {
if (state.attachment.processEntity(belt, entityIn, state)) {
info.ticksSinceLastCollision--;
return;
}
}
final Direction beltFacing = blockState.get(BlockStateProperties.HORIZONTAL_FACING);
final Slope slope = blockState.get(BeltBlock.SLOPE);
final Axis axis = beltFacing.getAxis();

View file

@ -0,0 +1,100 @@
package com.simibubi.create.content.contraptions.relays.belt.transport;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
public class BeltTunnelInteractionHandler {
public static boolean flapTunnelsAndCheckIfStuck(BeltInventory beltInventory, TransportedItemStack current,
float nextOffset) {
int currentSegment = (int) current.beltPosition;
int upcomingSegment = (int) nextOffset;
Direction movementFacing = beltInventory.belt.getMovementFacing();
if (!beltInventory.beltMovementPositive && nextOffset == 0)
upcomingSegment = -1;
if (currentSegment != upcomingSegment) {
if (stuckAtTunnel(beltInventory, upcomingSegment, current.stack, movementFacing))
return true;
if (!beltInventory.belt.getWorld().isRemote) {
flapTunnel(beltInventory, currentSegment, movementFacing, false);
flapTunnel(beltInventory, upcomingSegment, movementFacing.getOpposite(), true);
}
}
return false;
}
public static boolean stuckAtTunnel(BeltInventory beltInventory, int offset, ItemStack stack,
Direction movementDirection) {
BeltTileEntity belt = beltInventory.belt;
BlockPos pos = BeltHelper.getPositionForOffset(belt, offset)
.up();
if (!AllBlocks.BELT_TUNNEL.has(belt.getWorld()
.getBlockState(pos)))
return false;
TileEntity te = belt.getWorld()
.getTileEntity(pos);
if (te == null || !(te instanceof BeltTunnelTileEntity))
return false;
Direction flapFacing = movementDirection.getOpposite();
BeltTunnelTileEntity tunnel = (BeltTunnelTileEntity) te;
if (!tunnel.flaps.containsKey(flapFacing))
return false;
if (!tunnel.syncedFlaps.containsKey(flapFacing))
return false;
ItemStack heldItem = tunnel.syncedFlaps.get(flapFacing);
if (heldItem == null) {
tunnel.syncedFlaps.put(flapFacing, ItemStack.EMPTY);
belt.sendData();
return false;
}
if (heldItem == ItemStack.EMPTY) {
tunnel.syncedFlaps.put(flapFacing, stack);
return true;
}
List<BeltTunnelTileEntity> group = BeltTunnelBlock.getSynchronizedGroup(belt.getWorld(), pos, flapFacing);
for (BeltTunnelTileEntity otherTunnel : group)
if (otherTunnel.syncedFlaps.get(flapFacing) == ItemStack.EMPTY)
return true;
for (BeltTunnelTileEntity otherTunnel : group)
otherTunnel.syncedFlaps.put(flapFacing, null);
return true;
}
public static void flapTunnel(BeltInventory beltInventory, int offset, Direction side, boolean inward) {
BeltTileEntity belt = beltInventory.belt;
if (belt.getBlockState()
.get(BeltBlock.SLOPE) != Slope.HORIZONTAL)
return;
BlockPos pos = BeltHelper.getPositionForOffset(belt, offset)
.up();
if (!AllBlocks.BELT_TUNNEL.has(belt.getWorld()
.getBlockState(pos)))
return;
TileEntity te = belt.getWorld()
.getTileEntity(pos);
if (te == null || !(te instanceof BeltTunnelTileEntity))
return;
((BeltTunnelTileEntity) te).flap(side, inward ^ side.getAxis() == Axis.Z);
}
}

View file

@ -1,93 +1,25 @@
package com.simibubi.create.content.logistics.block.belts;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.content.logistics.block.AttachedLogisticalBlock;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.SingleTargetAutoExtractingBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
public abstract class BeltAttachableLogisticalBlock extends AttachedLogisticalBlock implements IBeltAttachment {
public abstract class BeltAttachableLogisticalBlock extends AttachedLogisticalBlock {
public BeltAttachableLogisticalBlock(Properties properties) {
super(properties);
}
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
onAttachmentPlaced(worldIn, pos, state);
}
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
onAttachmentRemoved(worldIn, pos, state);
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE);
worldIn.removeTileEntity(pos);
}
}
@Override
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
return pos.offset(getBlockFacing(state));
}
@Override
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
return Arrays.asList(Direction.values()).stream().filter(d -> d != Direction.UP).map(pos::offset)
.collect(Collectors.toList());
}
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
BlockPos pos = state.attachmentPos;
World world = te.getWorld();
ItemStack stack = transported.stack;
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
SingleTargetAutoExtractingBehaviour extracting = TileEntityBehaviour.get(world, pos,
SingleTargetAutoExtractingBehaviour.TYPE);
if (extracting == null)
return false;
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getAmount()))
return false;
return true;
}
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
BlockPos pos = state.attachmentPos;
World world = te.getWorld();
ItemStack stack = transported.stack;
SingleTargetAutoExtractingBehaviour extracting = TileEntityBehaviour.get(world, pos,
SingleTargetAutoExtractingBehaviour.TYPE);
if (extracting == null)
return false;
if (extracting.getShouldPause().get())
return false;
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getAmount()))
return false;
if (!extracting.getShouldExtract().get())
return true;
return !extracting.extractFromInventory();
}
}

View file

@ -1,33 +1,21 @@
package com.simibubi.create.content.logistics.block.belts.observer;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Part;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock.Slope;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
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.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.EnumProperty;
@ -37,18 +25,13 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public class BeltObserverBlock extends HorizontalBlock
implements ITE<BeltObserverTileEntity>, IBeltAttachment, IWrenchable {
implements ITE<BeltObserverTileEntity>, IWrenchable {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final BooleanProperty BELT = BooleanProperty.create("belt");
@ -138,23 +121,6 @@ public class BeltObserverBlock extends HorizontalBlock
return state;
}
@Override
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
Direction side = beltState.get(BeltBlock.HORIZONTAL_FACING).rotateY();
return Arrays.asList(pos.offset(side), pos.offset(side.getOpposite()));
}
@Override
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
return pos.offset(state.get(HORIZONTAL_FACING));
}
@Override
public boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos,
BlockState attachmentState, BlockState beltState) {
return attachmentState.get(BELT);
}
@Override
public boolean canProvidePower(BlockState state) {
return state.get(POWERED);
@ -172,118 +138,12 @@ public class BeltObserverBlock extends HorizontalBlock
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (newState.getBlock() != this || newState.with(POWERED, false) != state.with(POWERED, false))
onAttachmentRemoved(worldIn, pos, state);
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE);
worldIn.removeTileEntity(pos);
}
}
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
if (oldState.getBlock() != this || oldState.with(POWERED, false) != state.with(POWERED, false))
onAttachmentPlaced(worldIn, pos, state);
}
@Override
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
World world = te.getWorld();
BlockState blockState = world.getBlockState(state.attachmentPos);
if (blockState.get(MODE) == Mode.DETECT)
return false;
FilteringBehaviour behaviour =
TileEntityBehaviour.get(te.getWorld(), state.attachmentPos, FilteringBehaviour.TYPE);
if (behaviour != null && !behaviour.test(transported.stack))
return false;
world.setBlockState(state.attachmentPos, blockState.with(POWERED, true));
world.notifyNeighborsOfStateChange(state.attachmentPos, this);
withTileEntityDo(world, state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
Mode mode = blockState.get(MODE);
if (mode == Mode.EJECT || mode == Mode.SPLIT) {
ItemStack copy = transported.stack.copy();
ItemStack toEject = mode == Mode.EJECT ? transported.stack : copy.split(transported.stack.getCount() / 2);
if (!toEject.isEmpty()) {
if (!eject(world, toEject, state.attachmentPos, blockState.get(HORIZONTAL_FACING)))
return true;
transported.stack = mode == Mode.EJECT ? ItemStack.EMPTY : copy;
}
}
return false;
}
@Override
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
World world = te.getWorld();
BlockState blockState = world.getBlockState(state.attachmentPos);
withTileEntityDo(world, state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
Mode mode = blockState.get(MODE);
if (mode == Mode.EJECT || mode == Mode.SPLIT) {
ItemStack copy = transported.stack.copy();
ItemStack toEject = mode == Mode.EJECT ? transported.stack : copy.split(transported.stack.getCount() / 2);
if (!eject(world, toEject, state.attachmentPos, blockState.get(HORIZONTAL_FACING)))
return true;
transported.stack = mode == Mode.EJECT ? ItemStack.EMPTY : copy;
}
return false;
}
private boolean eject(World world, ItemStack stack, BlockPos observerPos, Direction facing) {
BlockPos potentialBeltPos = observerPos.offset(facing, 2);
TileEntity tileEntity = world.getTileEntity(potentialBeltPos);
if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity belt = (BeltTileEntity) tileEntity;
return belt.tryInsertingFromSide(facing, stack, false);
}
boolean empty = world.getBlockState(potentialBeltPos).getCollisionShape(world, potentialBeltPos).isEmpty();
float yOffset = empty ? 0 : .5f;
AxisAlignedBB bb = new AxisAlignedBB(empty ? potentialBeltPos : potentialBeltPos.up());
if (!world.getEntitiesWithinAABBExcludingEntity(null, bb).isEmpty())
return false;
Vec3d motion = new Vec3d(facing.getDirectionVec()).scale(1 / 16f);
Vec3d entityPos = VecHelper.getCenterOf(potentialBeltPos).add(0, yOffset + .25f, 0).subtract(motion);
ItemEntity entity = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, stack);
entity.setMotion(motion);
entity.setPickupDelay(5);
world.playSound(null, observerPos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, .1f);
world.addEntity(entity);
return true;
}
@Override
public boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
if (te.getWorld().isRemote)
return false;
if (entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos())) > .5f)
return false;
World world = te.getWorld();
BlockState blockState = world.getBlockState(state.attachmentPos);
if (blockState.get(POWERED))
return false;
world.setBlockState(state.attachmentPos, blockState.with(POWERED, true));
world.notifyNeighborsOfStateChange(state.attachmentPos, this);
withTileEntityDo(te.getWorld(), state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
return false;
}
@Override
public void scheduledTick(BlockState state, ServerWorld worldIn, BlockPos pos, Random random) {
worldIn.setBlockState(pos, state.with(POWERED, false), 2);
worldIn.notifyNeighborsOfStateChange(pos, this);
}
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
World world = context.getWorld();

View file

@ -106,7 +106,7 @@ public class ExtractorTileEntity extends SmartTileEntity {
BeltInventory inventory = controller.getInventory();
if (inventory == null)
return false;
if (!inventory.canInsertFrom(belt.index, Direction.UP))
if (!inventory.canInsertAtFromSide(belt.index, Direction.UP))
return false;
}
}

View file

@ -1,19 +1,14 @@
package com.simibubi.create.content.logistics.block.funnel;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.components.structureMovement.IPortableBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.content.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
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.transport.TransportedItemStack;
import com.simibubi.create.content.logistics.block.AttachedLogisticalBlock;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
@ -41,7 +36,7 @@ import net.minecraft.world.IWorld;
import net.minecraft.world.World;
public class FunnelBlock extends AttachedLogisticalBlock
implements IBeltAttachment, ITE<FunnelTileEntity>, IPortableBlock {
implements ITE<FunnelTileEntity>, IPortableBlock {
public static final BooleanProperty BELT = BooleanProperty.create("belt");
public static final MovementBehaviour MOVEMENT = new FunnelMovementBehaviour();
@ -131,7 +126,6 @@ public class FunnelBlock extends AttachedLogisticalBlock
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
onAttachmentPlaced(worldIn, pos, state);
if (worldIn.isRemote)
return;
@ -153,42 +147,12 @@ public class FunnelBlock extends AttachedLogisticalBlock
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
onAttachmentRemoved(worldIn, pos, state);
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE);
worldIn.removeTileEntity(pos);
}
}
@Override
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
return Arrays.asList(pos.up());
}
@Override
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
return pos.down();
}
@Override
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
return process(te, transported, state);
}
@Override
public boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos,
BlockState attachmentState, BlockState beltState) {
return !isVertical(attachmentState);
}
@Override
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
Direction movementFacing = te.getMovementFacing();
if (movementFacing != te.getWorld().getBlockState(state.attachmentPos).get(HORIZONTAL_FACING))
return false;
return process(te, transported, state);
}
@Override
public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
BlockRayTraceResult hit) {
@ -207,16 +171,6 @@ public class FunnelBlock extends AttachedLogisticalBlock
return ActionResultType.PASS;
}
public boolean process(BeltTileEntity belt, TransportedItemStack transported, BeltAttachmentState state) {
TileEntity te = belt.getWorld().getTileEntity(state.attachmentPos);
if (!(te instanceof FunnelTileEntity))
return false;
FunnelTileEntity funnel = (FunnelTileEntity) te;
ItemStack stack = funnel.tryToInsert(transported.stack);
transported.stack = stack;
return true;
}
public static class Vertical extends FunnelBlock {
public Vertical(Properties properties) {
super(properties);

View file

@ -6,7 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
@ -14,7 +14,7 @@ import net.minecraft.tileentity.TileEntityType;
public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity {
private Map<IBehaviourType<?>, TileEntityBehaviour> behaviours;
private Map<BehaviourType<?>, TileEntityBehaviour> behaviours;
private boolean initialized;
private boolean firstNbtRead;
private int lazyTickRate;
@ -120,14 +120,14 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
behaviour.initialize();
}
protected void removeBehaviour(IBehaviourType<?> type) {
protected void removeBehaviour(BehaviourType<?> type) {
TileEntityBehaviour remove = behaviours.remove(type);
if (remove != null)
remove.remove();
}
@SuppressWarnings("unchecked")
protected <T extends TileEntityBehaviour> T getBehaviour(IBehaviourType<T> type) {
protected <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) {
if (behaviours.containsKey(type))
return (T) behaviours.get(type);
return null;

View file

@ -1,6 +1,6 @@
package com.simibubi.create.foundation.tileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
@ -23,7 +23,7 @@ public abstract class TileEntityBehaviour {
setLazyTickRate(10);
}
public abstract IBehaviourType<?> getType();
public abstract BehaviourType<?> getType();
public void initialize() {
@ -91,18 +91,18 @@ public abstract class TileEntityBehaviour {
}
public static <T extends TileEntityBehaviour> T get(ILightReader reader, BlockPos pos,
IBehaviourType<T> type) {
BehaviourType<T> type) {
return get(reader.getTileEntity(pos), type);
}
public static <T extends TileEntityBehaviour> void destroy(ILightReader reader, BlockPos pos,
IBehaviourType<T> type) {
BehaviourType<T> type) {
T behaviour = get(reader.getTileEntity(pos), type);
if (behaviour != null)
behaviour.destroy();
}
public static <T extends TileEntityBehaviour> T get(TileEntity te, IBehaviourType<T> type) {
public static <T extends TileEntityBehaviour> T get(TileEntity te, BehaviourType<T> type) {
if (te == null)
return null;
if (!(te instanceof SmartTileEntity))

View file

@ -2,6 +2,6 @@ package com.simibubi.create.foundation.tileEntity.behaviour;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
public interface IBehaviourType<T extends TileEntityBehaviour> {
public class BehaviourType<T extends TileEntityBehaviour> {
}

View file

@ -0,0 +1,59 @@
package com.simibubi.create.foundation.tileEntity.behaviour.belt;
import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
/**
* Behaviour for TileEntities which can process items on belts or depots beneath them.
* Currently only supports placement location 2 spaces above the belt block.
* Example use: Mechanical Press
*/
public class BeltProcessingBehaviour extends TileEntityBehaviour {
public static BehaviourType<BeltProcessingBehaviour> TYPE = new BehaviourType<>();
public static enum ProcessingResult {
PASS, HOLD, REMOVE;
}
private ProcessingCallback onItemEnter;
private ProcessingCallback continueProcessing;
public BeltProcessingBehaviour(SmartTileEntity te) {
super(te);
onItemEnter = (s, i) -> ProcessingResult.PASS;
continueProcessing = (s, i) -> ProcessingResult.PASS;
}
public BeltProcessingBehaviour whenItemEnters(ProcessingCallback callback) {
onItemEnter = callback;
return this;
}
public BeltProcessingBehaviour whileItemHeld(ProcessingCallback callback) {
continueProcessing = callback;
return this;
}
@Override
public BehaviourType<?> getType() {
return TYPE;
}
public ProcessingResult handleReceivedItem(TransportedItemStack stack, BeltInventory inventory) {
return onItemEnter.apply(stack, inventory);
}
public ProcessingResult handleHeldItem(TransportedItemStack stack, BeltInventory inventory) {
return continueProcessing.apply(stack, inventory);
}
@FunctionalInterface
public interface ProcessingCallback {
public ProcessingResult apply(TransportedItemStack stack, BeltInventory inventory);
}
}

View file

@ -0,0 +1,76 @@
package com.simibubi.create.foundation.tileEntity.behaviour.belt;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
/**
* Behaviour for TileEntities to which belts can transfer items directly in a
* backup-friendly manner. Example uses: Basin, Saw, Depot
*/
public class DirectBeltInputBehaviour extends TileEntityBehaviour {
public static BehaviourType<DirectBeltInputBehaviour> TYPE = new BehaviourType<>();
private InsertionCallback tryInsert;
private AvailabilityPredicate canInsert;
public DirectBeltInputBehaviour(SmartTileEntity te) {
super(te);
tryInsert = this::defaultInsertionCallback;
canInsert = d -> true;
}
public DirectBeltInputBehaviour onlyInsertWhen(AvailabilityPredicate pred) {
canInsert = pred;
return this;
}
public DirectBeltInputBehaviour setInsertionHandler(InsertionCallback callback) {
tryInsert = callback;
return this;
}
private ItemStack defaultInsertionCallback(TransportedItemStack inserted, Direction side, boolean simulate) {
LazyOptional<IItemHandler> lazy = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side);
if (!lazy.isPresent())
return inserted.stack;
return ItemHandlerHelper.insertItemStacked(lazy.orElse(null), inserted.stack.copy(), simulate);
}
public boolean canInsertFromSide(Direction side) {
return canInsert.test(side);
}
public ItemStack handleInsertion(ItemStack stack, Direction side, boolean simulate) {
return handleInsertion(new TransportedItemStack(stack), side, simulate);
}
public ItemStack handleInsertion(TransportedItemStack stack, Direction side, boolean simulate) {
return tryInsert.apply(stack, side, simulate);
}
@Override
public BehaviourType<?> getType() {
return TYPE;
}
@FunctionalInterface
public interface InsertionCallback {
public ItemStack apply(TransportedItemStack stack, Direction side, boolean simulate);
}
@FunctionalInterface
public interface AvailabilityPredicate {
public boolean test(Direction side);
}
}

View file

@ -4,7 +4,7 @@ import java.util.Optional;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.item.Item;
import net.minecraft.util.Direction;
@ -13,8 +13,7 @@ import net.minecraft.world.World;
public class EdgeInteractionBehaviour extends TileEntityBehaviour {
public static IBehaviourType<EdgeInteractionBehaviour> TYPE = new IBehaviourType<EdgeInteractionBehaviour>() {
};
public static BehaviourType<EdgeInteractionBehaviour> TYPE = new BehaviourType<>();
ConnectionCallback connectionCallback;
ConnectivityPredicate connectivityPredicate;
@ -38,7 +37,7 @@ public class EdgeInteractionBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -7,7 +7,7 @@ import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.utility.VecHelper;
@ -20,8 +20,7 @@ import net.minecraft.world.World;
public class FilteringBehaviour extends TileEntityBehaviour {
public static IBehaviourType<FilteringBehaviour> TYPE = new IBehaviourType<FilteringBehaviour>() {
};
public static BehaviourType<FilteringBehaviour> TYPE = new BehaviourType<>();
ValueBoxTransform slotPositioning;
boolean showCount;
@ -152,7 +151,7 @@ public class FilteringBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -7,7 +7,7 @@ import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
@ -15,8 +15,7 @@ import net.minecraft.util.math.BlockPos;
public class AutoExtractingBehaviour extends ExtractingBehaviour {
public static IBehaviourType<AutoExtractingBehaviour> TYPE = new IBehaviourType<AutoExtractingBehaviour>() {
};
public static BehaviourType<AutoExtractingBehaviour> TYPE = new BehaviourType<>();
private int delay;
private int timer;
@ -85,7 +84,7 @@ public class AutoExtractingBehaviour extends ExtractingBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -11,7 +11,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import net.minecraft.item.ItemStack;
@ -21,8 +21,7 @@ import net.minecraftforge.items.IItemHandler;
public class ExtractingBehaviour extends InventoryManagementBehaviour {
public static IBehaviourType<ExtractingBehaviour> TYPE = new IBehaviourType<ExtractingBehaviour>() {
};
public static BehaviourType<ExtractingBehaviour> TYPE = new BehaviourType<>();
private Function<ItemStack, Integer> customAmountFilter;
private Predicate<ItemStack> customFilter;
@ -90,7 +89,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -6,7 +6,7 @@ import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
@ -16,8 +16,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
public class InsertingBehaviour extends InventoryManagementBehaviour {
public static IBehaviourType<InsertingBehaviour> TYPE = new IBehaviourType<InsertingBehaviour>() {
};
public static BehaviourType<InsertingBehaviour> TYPE = new BehaviourType<>();
public InsertingBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments) {
super(te, attachments);
@ -33,7 +32,7 @@ public class InsertingBehaviour extends InventoryManagementBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -11,7 +11,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
@ -28,8 +28,7 @@ public class InventoryManagementBehaviour extends TileEntityBehaviour {
private Supplier<List<Pair<BlockPos, Direction>>> attachments;
private List<IItemHandler> activeHandlers;
public static IBehaviourType<InventoryManagementBehaviour> TYPE = new IBehaviourType<InventoryManagementBehaviour>() {
};
public static BehaviourType<InventoryManagementBehaviour> TYPE = new BehaviourType<>();
public InventoryManagementBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments) {
super(te);
@ -98,7 +97,7 @@ public class InventoryManagementBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -4,7 +4,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
@ -13,16 +13,14 @@ import net.minecraft.util.math.BlockPos;
public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour {
public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE =
new IBehaviourType<SingleTargetAutoExtractingBehaviour>() {
};
public static BehaviourType<SingleTargetAutoExtractingBehaviour> TYPE = new BehaviourType<>();
private Supplier<Direction> attachmentDirection;
boolean synced;
boolean advantageOnNextSync;
public SingleTargetAutoExtractingBehaviour(SmartTileEntity te, Supplier<Direction> attachmentDirection,
Consumer<ItemStack> onExtract, int delay) {
Consumer<ItemStack> onExtract, int delay) {
super(te, Attachments.toward(attachmentDirection), onExtract, delay);
this.attachmentDirection = attachmentDirection;
synced = true;
@ -49,7 +47,8 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour
@Override
public boolean extract() {
if (synced) {
BlockPos invPos = tileEntity.getPos().offset(attachmentDirection.get());
BlockPos invPos = tileEntity.getPos()
.offset(attachmentDirection.get());
return SynchronizedExtraction.extractSynchronized(getWorld(), invPos);
} else
return extractFromInventory();
@ -60,7 +59,7 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -11,7 +11,7 @@ import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler.Frequency;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import net.minecraft.block.BlockState;
@ -21,8 +21,7 @@ import net.minecraft.util.math.Vec3d;
public class LinkBehaviour extends TileEntityBehaviour {
public static IBehaviourType<LinkBehaviour> TYPE = new IBehaviourType<LinkBehaviour>() {
};
public static BehaviourType<LinkBehaviour> TYPE = new BehaviourType<>();
enum Mode {
TRANSMIT, RECEIVE
@ -162,7 +161,7 @@ public class LinkBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -6,7 +6,7 @@ import java.util.function.Function;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import net.minecraft.block.BlockState;
@ -16,8 +16,7 @@ import net.minecraft.util.math.Vec3d;
public class ScrollValueBehaviour extends TileEntityBehaviour {
public static IBehaviourType<ScrollValueBehaviour> TYPE = new IBehaviourType<ScrollValueBehaviour>() {
};
public static BehaviourType<ScrollValueBehaviour> TYPE = new BehaviourType<>();
ValueBoxTransform slotPositioning;
Vec3d textShift;
@ -162,7 +161,7 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}

View file

@ -4,14 +4,13 @@ import java.util.function.Supplier;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.nbt.CompoundNBT;
public class DeferralBehaviour extends TileEntityBehaviour {
public static IBehaviourType<DeferralBehaviour> TYPE = new IBehaviourType<DeferralBehaviour>() {
};
public static BehaviourType<DeferralBehaviour> TYPE = new BehaviourType<>();
private boolean needsUpdate;
private Supplier<Boolean> callback;
@ -45,7 +44,7 @@ public class DeferralBehaviour extends TileEntityBehaviour {
}
@Override
public IBehaviourType<?> getType() {
public BehaviourType<?> getType() {
return TYPE;
}