diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 3dc452168..7c86504d4 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -72,6 +72,8 @@ import com.simibubi.create.content.logistics.block.belts.observer.BeltObserverRe import com.simibubi.create.content.logistics.block.belts.observer.BeltObserverTileEntity; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; +import com.simibubi.create.content.logistics.block.depot.DepotRenderer; +import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterRenderer; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterTileEntity; @@ -219,6 +221,8 @@ public class AllTileEntities { public static final TileEntityEntry CREATIVE_CRATE = register("creative_crate", CreativeCrateTileEntity::new, AllBlocks.CREATIVE_CRATE); + public static final TileEntityEntry DEPOT = + register("depot", DepotTileEntity::new, AllBlocks.DEPOT); public static final TileEntityEntry REALITY_FUNNEL = register("reality_funnel", RealityFunnelTileEntity::new, AllBlocks.REALITY_FUNNEL, AllBlocks.BELT_FUNNEL, AllBlocks.CHUTE_FUNNEL); public static final TileEntityEntry PACKAGER = @@ -295,6 +299,7 @@ public class AllTileEntities { bind(FURNACE_ENGINE, EngineRenderer::new); bind(ROTATION_SPEED_CONTROLLER, SpeedControllerRenderer::new); bind(PACKAGER, PackagerRenderer::new); + bind(DEPOT, DepotRenderer::new); bind(CREATIVE_CRATE, SmartTileEntityRenderer::new); bind(REDSTONE_LINK, SmartTileEntityRenderer::new); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java index 4d159e624..d9bf3a889 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java @@ -7,11 +7,12 @@ import java.util.List; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.content.contraptions.particle.AirFlowParticleData; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.logistics.InWorldProcessing; import com.simibubi.create.content.logistics.InWorldProcessing.Type; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; @@ -21,9 +22,7 @@ import net.minecraft.entity.EntityType; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.monster.EndermanEntity; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.SoundCategory; @@ -42,10 +41,10 @@ import net.minecraftforge.common.Tags; public class AirCurrent { - private static DamageSource damageSourceFire = - new DamageSource("create.fan_fire").setDifficultyScaled().setFireDamage(); - private static DamageSource damageSourceLava = - new DamageSource("create.fan_lava").setDifficultyScaled().setFireDamage(); + private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled() + .setFireDamage(); + private static DamageSource damageSourceLava = new DamageSource("create.fan_lava").setDifficultyScaled() + .setFireDamage(); public final EncasedFanTileEntity source; public AxisAlignedBB bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); @@ -54,7 +53,8 @@ public class AirCurrent { public boolean pushing; public float maxDistance; - protected List> affectedBelts = new ArrayList<>(); + protected List> affectedItemHandlers = + new ArrayList<>(); protected List caughtEntities = new ArrayList<>(); public AirCurrent(EncasedFanTileEntity source) { @@ -66,14 +66,16 @@ public class AirCurrent { Direction facing = direction; if (world.isRemote) { float offset = pushing ? 0.5f : maxDistance + .5f; - Vec3d pos = VecHelper.getCenterOf(source.getPos()).add(new Vec3d(facing.getDirectionVec()).scale(offset)); + Vec3d pos = VecHelper.getCenterOf(source.getPos()) + .add(new Vec3d(facing.getDirectionVec()).scale(offset)); if (world.rand.nextFloat() < AllConfigs.CLIENT.fanParticleDensity.get()) world.addParticle(new AirFlowParticleData(source.getPos()), pos.x, pos.y, pos.z, 0, 0, 0); } for (Iterator iterator = caughtEntities.iterator(); iterator.hasNext();) { Entity entity = iterator.next(); - if (!entity.getBoundingBox().intersects(bounds)) { + if (!entity.getBoundingBox() + .intersects(bounds)) { iterator.remove(); continue; } @@ -83,7 +85,8 @@ public class AirCurrent { float sneakModifier = entity.isSneaking() ? 4096f : 512f; float speed = Math.abs(source.getSpeed()); - double entityDistance = entity.getPositionVec().distanceTo(center); + double entityDistance = entity.getPositionVec() + .distanceTo(center); float acceleration = (float) (speed / sneakModifier / (entityDistance / maxDistance)); Vec3d previousMotion = entity.getMotion(); float maxAcceleration = 5; @@ -127,15 +130,16 @@ public class AirCurrent { } break; case SPLASHING: - if (entity instanceof EndermanEntity || entity.getType() == EntityType.SNOW_GOLEM || entity.getType() == EntityType.BLAZE) { + if (entity instanceof EndermanEntity || entity.getType() == EntityType.SNOW_GOLEM + || entity.getType() == EntityType.BLAZE) { entity.attackEntityFrom(DamageSource.DROWN, 2); } if (!entity.isBurning()) break; entity.extinguish(); world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, - SoundCategory.NEUTRAL, 0.7F, - 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); + SoundCategory.NEUTRAL, 0.7F, + 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); break; default: break; @@ -145,7 +149,7 @@ public class AirCurrent { } - tickBelts(); + tickAffectedHandlers(); } public void rebuild() { @@ -158,7 +162,8 @@ public class AirCurrent { World world = source.getWorld(); BlockPos start = source.getPos(); - direction = source.getBlockState().get(BlockStateProperties.FACING); + direction = source.getBlockState() + .get(BlockStateProperties.FACING); pushing = source.getAirFlowDirection() == direction; Vec3d directionVec = new Vec3d(direction.getDirectionVec()); Vec3d planeVec = VecHelper.planeByNormal(directionVec); @@ -166,9 +171,9 @@ public class AirCurrent { // 4 Rays test for holes in the shapes blocking the flow float offsetDistance = .25f; Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance), - planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance), - planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance), - planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), }; + planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance), + planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance), + planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), }; maxDistance = source.getMaxDistance(); float limitedDistance = 0; @@ -190,15 +195,17 @@ public class AirCurrent { } for (Vec3d offset : offsets) { - Vec3d rayStart = - VecHelper.getCenterOf(currentPos).subtract(directionVec.scale(.5f + 1 / 32f)).add(offset); + Vec3d rayStart = VecHelper.getCenterOf(currentPos) + .subtract(directionVec.scale(.5f + 1 / 32f)) + .add(offset); Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f)); BlockRayTraceResult blockraytraceresult = world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, state); if (blockraytraceresult == null) continue Outer; - double distance = i - 1 + blockraytraceresult.getHitVec().distanceTo(rayStart); + double distance = i - 1 + blockraytraceresult.getHitVec() + .distanceTo(rayStart); if (limitedDistance < distance) limitedDistance = (float) distance; } @@ -244,68 +251,58 @@ public class AirCurrent { if (factor > 0) bounds = new AxisAlignedBB(start.offset(direction)).expand(scale); else { - bounds = new AxisAlignedBB(start.offset(direction)).contract(scale.x, scale.y, scale.z).offset(scale); + bounds = new AxisAlignedBB(start.offset(direction)).contract(scale.x, scale.y, scale.z) + .offset(scale); } } - findAffectedBelts(); + findAffectedHandlers(); } public void findEntities() { caughtEntities.clear(); - caughtEntities = source.getWorld().getEntitiesWithinAABBExcludingEntity(null, bounds); + caughtEntities = source.getWorld() + .getEntitiesWithinAABBExcludingEntity(null, bounds); } - public void findAffectedBelts() { + public void findAffectedHandlers() { World world = source.getWorld(); BlockPos start = source.getPos(); - affectedBelts.clear(); + affectedItemHandlers.clear(); for (int i = 0; i < maxDistance + 1; i++) { Type type = getSegmentAt(i); if (type == null) continue; - BlockPos pos = start.offset(direction, i); - TileEntity te = world.getTileEntity(pos); - if (te != null && (te instanceof BeltTileEntity)) - affectedBelts.add(Pair.of((BeltTileEntity) te, type)); - if (direction.getAxis().isVertical()) - continue; - pos = pos.down(); - te = world.getTileEntity(pos); - if (te == null || !(te instanceof BeltTileEntity)) - continue; - affectedBelts.add(Pair.of((BeltTileEntity) te, type)); + for (int offset : Iterate.zeroAndOne) { + BlockPos pos = start.offset(direction, i) + .down(offset); + TransportedItemStackHandlerBehaviour behaviour = + TileEntityBehaviour.get(world, pos, TransportedItemStackHandlerBehaviour.TYPE); + if (behaviour != null) + affectedItemHandlers.add(Pair.of(behaviour, type)); + if (direction.getAxis() + .isVertical()) + break; + } } } - public void tickBelts() { - for (Pair pair : affectedBelts) { - BeltTileEntity belt = pair.getKey(); - World world = belt.getWorld(); + public void tickAffectedHandlers() { + for (Pair pair : affectedItemHandlers) { + TransportedItemStackHandlerBehaviour handler = pair.getKey(); + World world = handler.getWorld(); InWorldProcessing.Type processingType = pair.getRight(); - BeltTileEntity controller = belt.getControllerTE(); - if (controller == null) - continue; - - controller.getInventory().forEachWithin(belt.index + .5f, .51f, (transported) -> { - InWorldProcessing.spawnParticlesForProcessing(world, - BeltHelper.getVectorForOffset(controller, transported.beltPosition), processingType); + handler.handleProcessingOnAllItems((transported) -> { + InWorldProcessing.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported), + processingType); if (world.isRemote) return null; - return InWorldProcessing.applyProcessing(transported, belt, processingType); + return InWorldProcessing.applyProcessing(transported, world, processingType); }); } } - public void writeToNBT(CompoundNBT nbt) { - - } - - public void readFromNBT(CompoundNBT nbt) { - - } - private static boolean shouldAlwaysPass(BlockState state) { if (state.isIn(Tags.Blocks.FENCES)) return true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java index da9f3f539..2c86155b3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java @@ -7,17 +7,17 @@ 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 com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; import net.minecraft.item.ItemStack; public class BeltPressingCallbacks { - static ProcessingResult onItemReceived(TransportedItemStack transported, BeltInventory beltInventory, - MechanicalPressTileEntity press) { + static ProcessingResult onItemReceived(TransportedItemStack transported, + TransportedItemStackHandlerBehaviour handler, MechanicalPressTileEntity press) { if (press.getSpeed() == 0 || press.running) return PASS; if (!press.getRecipe(transported.stack) @@ -28,9 +28,9 @@ public class BeltPressingCallbacks { return HOLD; } - static ProcessingResult whenItemHeld(TransportedItemStack transportedStack, BeltInventory beltInventory, + static ProcessingResult whenItemHeld(TransportedItemStack transported, TransportedItemStackHandlerBehaviour handler, MechanicalPressTileEntity pressTe) { - + if (pressTe.getSpeed() == 0) return PASS; if (!pressTe.running) @@ -38,9 +38,9 @@ public class BeltPressingCallbacks { if (pressTe.runningTicks != 30) return HOLD; - Optional recipe = pressTe.getRecipe(transportedStack.stack); + Optional recipe = pressTe.getRecipe(transported.stack); pressTe.pressedItems.clear(); - pressTe.pressedItems.add(transportedStack.stack); + pressTe.pressedItems.add(transported.stack); if (!recipe.isPresent()) return PASS; @@ -48,10 +48,10 @@ public class BeltPressingCallbacks { ItemStack out = recipe.get() .getRecipeOutput() .copy(); - List multipliedOutput = ItemHelper.multipliedOutput(transportedStack.stack, out); + List multipliedOutput = ItemHelper.multipliedOutput(transported.stack, out); if (multipliedOutput.isEmpty()) - transportedStack.stack = ItemStack.EMPTY; - transportedStack.stack = multipliedOutput.get(0); + transported.stack = ItemStack.EMPTY; + transported.stack = multipliedOutput.get(0); pressTe.sendData(); return HOLD; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java index a34721af3..ccd5995bd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java @@ -250,7 +250,7 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE { + .applyToEachWithin(belt.index + .5f, .55f, (transportedItemStack) -> { player.inventory.placeItemBackInInventory(worldIn, transportedItemStack.stack); return Collections.emptyList(); }); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index 0c2690f91..90d9dba00 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -24,6 +25,7 @@ import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandle 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.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; import com.simibubi.create.foundation.utility.ColorHelper; import net.minecraft.block.BlockState; @@ -39,6 +41,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -72,6 +75,8 @@ public class BeltTileEntity extends KineticTileEntity { behaviours.add(new DirectBeltInputBehaviour(this) .onlyInsertWhen(d -> getSpeed() != 0 && getMovementFacing() != d.getOpposite()) .setInsertionHandler(this::tryInsertingFromSide)); + behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) + .withStackPlacement(this::getWorldPositionOf)); } @Override @@ -333,6 +338,20 @@ public class BeltTileEntity extends KineticTileEntity { return inventory; } + private void applyToAllItems(Function> processFunction) { + BeltTileEntity controller = getControllerTE(); + if (controller != null) + controller.getInventory() + .applyToEachWithin(index + .5f, .51f, processFunction); + } + + private Vec3d getWorldPositionOf(TransportedItemStack transported) { + BeltTileEntity controllerTE = getControllerTE(); + if (controllerTE == null) + return Vec3d.ZERO; + return BeltHelper.getVectorForOffset(controllerTE, transported.beltPosition); + } + /** * always target a DirectBeltInsertionBehaviour */ diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java index 915586ed7..2106571e9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java @@ -18,6 +18,7 @@ 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.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import net.minecraft.block.Block; @@ -165,7 +166,7 @@ public class BeltInventory { continue; if (!inputBehaviour.canInsertFromSide(movementFacing)) continue; - + ItemStack remainder = inputBehaviour.handleInsertion(currentItem, movementFacing, false); if (remainder.equals(currentItem.stack, false)) continue; @@ -198,14 +199,18 @@ public class BeltInventory { // Continue processing if held if (currentItem.locked) { BeltProcessingBehaviour processingBehaviour = getBeltProcessingAtSegment(currentSegment); + TransportedItemStackHandlerBehaviour stackHandlerBehaviour = + getTransportedItemStackHandlerAtSegment(currentSegment); + if (stackHandlerBehaviour == null) + return false; if (processingBehaviour == null) { currentItem.locked = false; belt.sendData(); return false; } - ProcessingResult result = processingBehaviour.handleHeldItem(currentItem, this); + ProcessingResult result = processingBehaviour.handleHeldItem(currentItem, stackHandlerBehaviour); if (result == ProcessingResult.REMOVE) return true; if (result == ProcessingResult.HOLD) @@ -225,10 +230,17 @@ public class BeltInventory { : segment + .5f >= nextOffset; segment += step) { BeltProcessingBehaviour processingBehaviour = getBeltProcessingAtSegment(segment); + TransportedItemStackHandlerBehaviour stackHandlerBehaviour = + getTransportedItemStackHandlerAtSegment(segment); + if (processingBehaviour == null) continue; + if (stackHandlerBehaviour == null) + continue; + if (BeltProcessingBehaviour.isBlocked(belt.getWorld(), BeltHelper.getPositionForOffset(belt, segment))) + continue; - ProcessingResult result = processingBehaviour.handleReceivedItem(currentItem, this); + ProcessingResult result = processingBehaviour.handleReceivedItem(currentItem, stackHandlerBehaviour); if (result == ProcessingResult.REMOVE) return true; @@ -249,6 +261,11 @@ public class BeltInventory { .up(2), BeltProcessingBehaviour.TYPE); } + protected TransportedItemStackHandlerBehaviour getTransportedItemStackHandlerAtSegment(int segment) { + return TileEntityBehaviour.get(belt.getWorld(), BeltHelper.getPositionForOffset(belt, segment), + TransportedItemStackHandlerBehaviour.TYPE); + } + private enum Ending { UNRESOLVED(0), EJECT(0), INSERT(.25f), FUNNEL(.35f), BLOCKED(.45f); @@ -373,22 +390,25 @@ public class BeltInventory { belt.getWorld() .addEntity(entity); } - + public void ejectAll() { items.forEach(this::eject); items.clear(); } - public void forEachWithin(float position, float distance, - Function> callback) { + public void applyToEachWithin(float position, float maxDistanceToPosition, + Function> processFunction) { List toBeAdded = new ArrayList<>(); boolean dirty = false; for (Iterator iterator = items.iterator(); iterator.hasNext();) { TransportedItemStack transportedItemStack = iterator.next(); - if (Math.abs(position - transportedItemStack.beltPosition) < distance) { - List apply = callback.apply(transportedItemStack); + ItemStack stackBefore = transportedItemStack.stack.copy(); + if (Math.abs(position - transportedItemStack.beltPosition) < maxDistanceToPosition) { + List apply = processFunction.apply(transportedItemStack); if (apply == null) continue; + if (apply.size() == 1 && apply.get(0).stack.equals(stackBefore, false)) + continue; dirty = true; toBeAdded.addAll(apply); iterator.remove(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java index 3b5f91c4c..e057d7ef4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java @@ -54,6 +54,7 @@ public class TransportedItemStack implements Comparable { public TransportedItemStack copy() { TransportedItemStack copy = getSimilar(); copy.angle = angle; + copy.sideOffset = sideOffset; return copy; } diff --git a/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java b/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java index 88739c43a..b2765dd7d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java +++ b/src/main/java/com/simibubi/create/content/logistics/InWorldProcessing.java @@ -8,7 +8,6 @@ import java.util.Optional; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.ItemHelper; @@ -61,7 +60,7 @@ public class InWorldProcessing { if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER) return Type.SPLASHING; if (blockState.getBlock() == Blocks.FIRE - || (blockState.getBlock() == Blocks.CAMPFIRE && blockState.get(CampfireBlock.LIT))) + || (blockState.getBlock() == Blocks.CAMPFIRE && blockState.get(CampfireBlock.LIT))) return Type.SMOKING; if (blockState.getBlock() == Blocks.LAVA) return Type.BLASTING; @@ -70,8 +69,10 @@ public class InWorldProcessing { } public static boolean canProcess(ItemEntity entity, Type type) { - if (entity.getPersistentData().contains("CreateData")) { - CompoundNBT compound = entity.getPersistentData().getCompound("CreateData"); + if (entity.getPersistentData() + .contains("CreateData")) { + CompoundNBT compound = entity.getPersistentData() + .getCompound("CreateData"); if (compound.contains("Processing")) { CompoundNBT processing = compound.getCompound("Processing"); @@ -100,7 +101,8 @@ public class InWorldProcessing { SmokerTileEntity smoker = new SmokerTileEntity(); smoker.setLocation(world, BlockPos.ZERO); smoker.setInventorySlotContents(0, stack); - Optional recipe = world.getRecipeManager().getRecipe(IRecipeType.SMOKING, smoker, world); + Optional recipe = world.getRecipeManager() + .getRecipe(IRecipeType.SMOKING, smoker, world); return recipe.isPresent(); } @@ -112,8 +114,8 @@ public class InWorldProcessing { public static boolean isWashable(ItemStack stack, World world) { splashingInv.setInventorySlotContents(0, stack); - Optional recipe = - world.getRecipeManager().getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); + Optional recipe = world.getRecipeManager() + .getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); return recipe.isPresent(); } @@ -135,15 +137,15 @@ public class InWorldProcessing { } } - public static List applyProcessing(TransportedItemStack transported, BeltTileEntity belt, - Type type) { + public static List applyProcessing(TransportedItemStack transported, + World world, Type type) { if (transported.processedBy != type) { transported.processedBy = type; int timeModifierForStackSize = ((transported.stack.getCount() - 1) / 16) + 1; int processingTime = (int) (AllConfigs.SERVER.kinetics.inWorldProcessingTime.get() * timeModifierForStackSize) + 1; transported.processingTime = processingTime; - if (!canProcess(transported.stack, type, belt.getWorld())) + if (!canProcess(transported.stack, type, world)) transported.processingTime = -1; return null; } @@ -152,15 +154,13 @@ public class InWorldProcessing { if (transported.processingTime-- > 0) return null; - List stacks = process(transported.stack, type, belt.getWorld()); + List stacks = process(transported.stack, type, world); if (stacks == null) return null; - + List transportedStacks = new ArrayList<>(); for (ItemStack additional : stacks) { TransportedItemStack newTransported = transported.getSimilar(); - newTransported.beltPosition -= Math.signum(belt.getDirectionAwareBeltMovementSpeed()) * 1/32f; - newTransported.prevBeltPosition = newTransported.beltPosition; newTransported.stack = additional.copy(); transportedStacks.add(newTransported); } @@ -170,8 +170,8 @@ public class InWorldProcessing { private static List process(ItemStack stack, Type type, World world) { if (type == Type.SPLASHING) { splashingInv.setInventorySlotContents(0, stack); - Optional recipe = - world.getRecipeManager().getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); + Optional recipe = world.getRecipeManager() + .getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world); if (recipe.isPresent()) return applyRecipeOn(stack, recipe.get()); return null; @@ -181,15 +181,16 @@ public class InWorldProcessing { SmokerTileEntity smoker = new SmokerTileEntity(); smoker.setLocation(world, BlockPos.ZERO); smoker.setInventorySlotContents(0, stack); - Optional smokingRecipe = world.getRecipeManager().getRecipe(IRecipeType.SMOKING, smoker, world); + Optional smokingRecipe = world.getRecipeManager() + .getRecipe(IRecipeType.SMOKING, smoker, world); if (type == Type.BLASTING) { // FIXME this does not need to be a TE FurnaceTileEntity furnace = new FurnaceTileEntity(); furnace.setLocation(world, BlockPos.ZERO); furnace.setInventorySlotContents(0, stack); - Optional smeltingRecipe = - world.getRecipeManager().getRecipe(IRecipeType.SMELTING, furnace, world); + Optional smeltingRecipe = world.getRecipeManager() + .getRecipe(IRecipeType.SMELTING, furnace, world); if (!smokingRecipe.isPresent()) { if (smeltingRecipe.isPresent()) @@ -199,8 +200,8 @@ public class InWorldProcessing { BlastFurnaceTileEntity blastFurnace = new BlastFurnaceTileEntity(); blastFurnace.setLocation(world, BlockPos.ZERO); blastFurnace.setInventorySlotContents(0, stack); - Optional blastingRecipe = - world.getRecipeManager().getRecipe(IRecipeType.BLASTING, blastFurnace, world); + Optional blastingRecipe = world.getRecipeManager() + .getRecipe(IRecipeType.BLASTING, blastFurnace, world); if (blastingRecipe.isPresent()) return applyRecipeOn(stack, blastingRecipe.get()); @@ -228,7 +229,8 @@ public class InWorldProcessing { if (!processing.contains("Type") || Type.valueOf(processing.getString("Type")) != type) { processing.putString("Type", type.name()); - int timeModifierForStackSize = ((entity.getItem().getCount() - 1) / 16) + 1; + int timeModifierForStackSize = ((entity.getItem() + .getCount() - 1) / 16) + 1; int processingTime = (int) (AllConfigs.SERVER.kinetics.inWorldProcessingTime.get() * timeModifierForStackSize) + 1; processing.putInt("Time", processingTime); @@ -269,7 +271,7 @@ public class InWorldProcessing { if (!ItemHandlerHelper.canItemStacksStack(stack, previouslyRolled)) continue; int amount = Math.min(previouslyRolled.getMaxStackSize() - previouslyRolled.getCount(), - stack.getCount()); + stack.getCount()); previouslyRolled.grow(amount); stack.shrink(amount); } @@ -281,7 +283,8 @@ public class InWorldProcessing { } } } else { - ItemStack out = recipe.getRecipeOutput().copy(); + ItemStack out = recipe.getRecipeOutput() + .copy(); stacks = ItemHelper.multipliedOutput(stackIn, out); } @@ -304,10 +307,10 @@ public class InWorldProcessing { case SPLASHING: Vec3d color = ColorHelper.getRGB(0x0055FF); world.addParticle(new RedstoneParticleData((float) color.x, (float) color.y, (float) color.z, 1), - vec.x + (world.rand.nextFloat() - .5f) * .5f, vec.y + .5f, - vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + vec.x + (world.rand.nextFloat() - .5f) * .5f, vec.y + .5f, vec.z + (world.rand.nextFloat() - .5f) * .5f, + 0, 1 / 8f, 0); world.addParticle(ParticleTypes.SPIT, vec.x + (world.rand.nextFloat() - .5f) * .5f, vec.y + .5f, - vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); break; default: break; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java index f56148779..b423dadfa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java @@ -53,7 +53,7 @@ public class BeltObserverTileEntity extends SmartTileEntity { if (controllerTE == null) return; - controllerTE.getInventory().forEachWithin(beltTE.index + .5f, .45f, stack -> { + controllerTE.getInventory().applyToEachWithin(beltTE.index + .5f, .45f, stack -> { if (filtering.test(stack.stack) && turnOffTicks != 6) { world.setBlockState(pos, getBlockState().with(BeltObserverBlock.POWERED, true)); world.notifyNeighborsOfStateChange(pos, getBlockState().getBlock()); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java index 280e2eb3c..a5aa60646 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java @@ -1,24 +1,132 @@ package com.simibubi.create.content.logistics.block.depot; +import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTileEntities; +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 com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.InventoryHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraftforge.items.ItemStackHandler; -public class DepotBlock extends Block { +public class DepotBlock extends Block implements ITE { public DepotBlock(Properties p_i48440_1_) { super(p_i48440_1_); } - + @Override public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_, ISelectionContext p_220053_4_) { return AllShapes.DEPOT; } + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return AllTileEntities.DEPOT.create(); + } + + @Override + public Class getTileEntityClass() { + return DepotTileEntity.class; + } + + @Override + public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockRayTraceResult ray) { + if (ray.getFace() != Direction.UP) + return ActionResultType.PASS; + if (world.isRemote) + return ActionResultType.SUCCESS; + + withTileEntityDo(world, pos, te -> { + boolean wasEmptyHanded = player.getHeldItem(hand) + .isEmpty(); + + ItemStack mainItemStack = te.getHeldItemStack(); + if (!mainItemStack.isEmpty()) { + player.inventory.placeItemBackInInventory(world, mainItemStack); + te.setHeldItem(null); + } + ItemStackHandler outputs = te.processingOutputBuffer; + for (int i = 0; i < outputs.getSlots(); i++) + player.inventory.placeItemBackInInventory(world, outputs.extractItem(i, 64, false)); + + if (!wasEmptyHanded) { + TransportedItemStack heldItem = new TransportedItemStack(player.getHeldItem(hand)); + heldItem.insertedFrom = player.getHorizontalFacing(); + heldItem.prevBeltPosition = .25f; + heldItem.beltPosition = .25f; + te.setHeldItem(heldItem); + player.setHeldItem(hand, ItemStack.EMPTY); + } + + te.markDirty(); + te.sendData(); + }); + + return ActionResultType.SUCCESS; + } + + @Override + public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (!state.hasTileEntity() || state.getBlock() == newState.getBlock()) { + return; + } + + withTileEntityDo(worldIn, pos, te -> { + ItemHelper.dropContents(worldIn, pos, te.processingOutputBuffer); + if (!te.getHeldItemStack() + .isEmpty()) + InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), te.getHeldItemStack()); + }); + worldIn.removeTileEntity(pos); + } + + @Override + public void onLanded(IBlockReader worldIn, Entity entityIn) { + super.onLanded(worldIn, entityIn); + if (!AllBlocks.DEPOT.has(worldIn.getBlockState(entityIn.getPosition()))) + return; + if (!(entityIn instanceof ItemEntity)) + return; + if (!entityIn.isAlive()) + return; + if (entityIn.world.isRemote) + return; + ItemEntity itemEntity = (ItemEntity) entityIn; + DirectBeltInputBehaviour inputBehaviour = + TileEntityBehaviour.get(worldIn, entityIn.getPosition(), DirectBeltInputBehaviour.TYPE); + if (inputBehaviour == null) + return; + ItemStack remainder = inputBehaviour.handleInsertion(itemEntity.getItem(), Direction.DOWN, false); + itemEntity.setItem(remainder); + if (remainder.isEmpty()) + itemEntity.remove(); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java new file mode 100644 index 000000000..c67813496 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.logistics.block.depot; + +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +public class DepotItemHandler implements IItemHandler { + + private static final int MAIN_SLOT = 0; + private DepotTileEntity te; + + public DepotItemHandler(DepotTileEntity te) { + this.te = te; + } + + @Override + public int getSlots() { + return 9; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return slot == MAIN_SLOT ? te.getHeldItemStack() : te.processingOutputBuffer.getStackInSlot(slot - 1); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (slot != MAIN_SLOT) + return stack; + if (!te.getHeldItemStack() + .isEmpty()) + return stack; + if (!te.isOutputEmpty()) + return stack; + if (!simulate) { + te.setHeldItem(new TransportedItemStack(stack)); + te.markDirty(); + te.sendData(); + } + return ItemStack.EMPTY; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (slot != MAIN_SLOT) + return te.processingOutputBuffer.extractItem(slot - 1, amount, simulate); + + TransportedItemStack held = te.heldItem; + if (held == null) + return ItemStack.EMPTY; + ItemStack stack = held.stack.copy(); + ItemStack extracted = stack.split(amount); + if (!simulate) { + te.heldItem.stack = stack; + if (stack.isEmpty()) + te.heldItem = null; + te.markDirty(); + te.sendData(); + } + return extracted; + } + + @Override + public int getSlotLimit(int slot) { + return 64; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return slot == MAIN_SLOT; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java new file mode 100644 index 000000000..85100bbe6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java @@ -0,0 +1,107 @@ +package com.simibubi.create.content.logistics.block.depot; + +import java.util.Random; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class DepotRenderer extends SafeTileEntityRenderer { + + public DepotRenderer(TileEntityRendererDispatcher dispatcher) { + super(dispatcher); + } + + @Override + protected void renderSafe(DepotTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, + int light, int overlay) { + + TransportedItemStack transported = te.heldItem; + MatrixStacker msr = MatrixStacker.of(ms); + + ms.push(); + ms.translate(.5f, 15 / 16f, .5f); + + // Render main item + if (transported != null) { + ms.push(); + msr.nudge(0); + float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition); + float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset); + Vec3d offsetVec = new Vec3d(transported.insertedFrom.getOpposite() + .getDirectionVec()).scale(.5f - offset); + ms.translate(offsetVec.x, offsetVec.y, offsetVec.z); + + if (transported.insertedFrom.getAxis() + .isHorizontal()) { + boolean alongX = transported.insertedFrom.rotateY() + .getAxis() == Axis.X; + if (!alongX) + sideOffset *= -1; + ms.translate(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset); + } + + ItemStack itemStack = transported.stack; + int angle = transported.angle; + Random r = new Random(0); + renderItem(ms, buffer, light, overlay, itemStack, angle, r); + ms.pop(); + } + + // Render output items + for (int i = 0; i < te.processingOutputBuffer.getSlots(); i++) { + ItemStack stack = te.processingOutputBuffer.getStackInSlot(i); + if (stack.isEmpty()) + continue; + ms.push(); + msr.nudge(i); + msr.rotateY(360 / 8f * i); + ms.translate(.35f, 0, 0); + Random r = new Random(i + 1); + int angle = (int) (360 * r.nextFloat()); + renderItem(ms, buffer, light, overlay, stack, angle, r); + ms.pop(); + } + + ms.pop(); + } + + protected void renderItem(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay, ItemStack itemStack, + int angle, Random r) { + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + MatrixStacker msr = MatrixStacker.of(ms); + int count = (int) (MathHelper.log2((int) (itemStack.getCount()))) / 2; + boolean blockItem = itemRenderer.getItemModelWithOverrides(itemStack, null, null) + .isGui3d(); + for (int i = 0; i <= count; i++) { + ms.push(); + msr.rotateY(angle); + if (!blockItem) { + ms.translate(0, -.09375, 0); + msr.rotateX(90); + } + if (blockItem) + ms.translate(r.nextFloat() * .0625f * i, 0, r.nextFloat() * .0625f * i); + ms.scale(.5f, .5f, .5f); + itemRenderer.renderItem(itemStack, TransformType.FIXED, light, overlay, ms, buffer); + ms.pop(); + + if (!blockItem) + msr.rotateY(10); + ms.translate(0, blockItem ? 1 / 64d : 1 / 16d, 0); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java new file mode 100644 index 000000000..414a6083b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java @@ -0,0 +1,203 @@ +package com.simibubi.create.content.logistics.block.depot; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +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.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.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.ItemStackHandler; + +public class DepotTileEntity extends SmartTileEntity { + + TransportedItemStack heldItem; + ItemStackHandler processingOutputBuffer; + + DepotItemHandler itemHandler; + LazyOptional lazyItemHandler; + + public DepotTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + itemHandler = new DepotItemHandler(this); + lazyItemHandler = LazyOptional.of(() -> itemHandler); + processingOutputBuffer = new ItemStackHandler(8) { + protected void onContentsChanged(int slot) { + markDirty(); + sendData(); + }; + }; + } + + @Override + public void tick() { + super.tick(); + if (heldItem == null) + return; + + heldItem.prevBeltPosition = heldItem.beltPosition; + heldItem.prevSideOffset = heldItem.sideOffset; + float diff = .5f - heldItem.beltPosition; + if (diff > 1 / 512f) { + if (diff > 1 / 32f) + heldItem.angle += 1; + heldItem.beltPosition += diff / 4f; + } + + if (diff > 1 / 16f) + return; + if (world.isRemote) + return; + + BeltProcessingBehaviour processingBehaviour = + TileEntityBehaviour.get(world, pos.up(2), BeltProcessingBehaviour.TYPE); + if (processingBehaviour == null) + return; + if (!heldItem.locked && BeltProcessingBehaviour.isBlocked(world, pos)) + return; + + boolean wasLocked = heldItem.locked; + ItemStack previousItem = heldItem.stack; + TransportedItemStackHandlerBehaviour handler = getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); + ProcessingResult result = wasLocked ? processingBehaviour.handleHeldItem(heldItem, handler) + : processingBehaviour.handleReceivedItem(heldItem, handler); + if (result == ProcessingResult.REMOVE) { + heldItem = null; + sendData(); + return; + } + + heldItem.locked = result == ProcessingResult.HOLD; + if (heldItem.locked != wasLocked || !previousItem.equals(heldItem.stack, false)) + sendData(); + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + if (heldItem != null) + compound.put("HeldItem", heldItem.serializeNBT()); + compound.put("OutputBuffer", processingOutputBuffer.serializeNBT()); + return super.write(compound); + } + + @Override + public void read(CompoundNBT compound) { + heldItem = null; + if (compound.contains("HeldItem")) + heldItem = TransportedItemStack.read(compound.getCompound("HeldItem")); + processingOutputBuffer.deserializeNBT(compound.getCompound("OutputBuffer")); + super.read(compound); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this).setInsertionHandler(this::tryInsertingFromSide)); + behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) + .withStackPlacement(this::getWorldPositionOf)); + } + + public ItemStack getHeldItemStack() { + return heldItem == null ? ItemStack.EMPTY : heldItem.stack; + } + + public void setHeldItem(TransportedItemStack heldItem) { + this.heldItem = heldItem; + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return lazyItemHandler.cast(); + return super.getCapability(cap, side); + } + + private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { + ItemStack inserted = transportedStack.stack; + ItemStack empty = ItemStack.EMPTY; + + if (!getHeldItemStack().isEmpty()) + return inserted; + if (!isOutputEmpty()) + return inserted; + if (simulate) + return empty; + + transportedStack = transportedStack.copy(); + transportedStack.beltPosition = side.getAxis() + .isVertical() ? .5f : 0; + transportedStack.insertedFrom = side; + transportedStack.prevSideOffset = transportedStack.sideOffset; + transportedStack.prevBeltPosition = transportedStack.beltPosition; + setHeldItem(transportedStack); + markDirty(); + sendData(); + + return empty; + } + + private void applyToAllItems(Function> processFunction) { + if (heldItem == null) + return; + + boolean dirty = false; + List toBeAdded = new ArrayList<>(); + TransportedItemStack transportedItemStack = heldItem; + ItemStack stackBefore = transportedItemStack.stack.copy(); + List apply = processFunction.apply(transportedItemStack); + + if (apply == null) + return; + if (apply.size() == 1 && apply.get(0).stack.equals(stackBefore, false)) + return; + + dirty = true; + heldItem = null; + toBeAdded.addAll(apply); + for (TransportedItemStack added : toBeAdded) { + if (heldItem == null) { + heldItem = added; + heldItem.beltPosition = 0.5f; + heldItem.prevBeltPosition = 0.5f; + continue; + } + for (int i = 0; i < processingOutputBuffer.getSlots(); i++) { + ItemStack stackInSlot = processingOutputBuffer.getStackInSlot(i); + if (!stackInSlot.isEmpty()) + continue; + processingOutputBuffer.setStackInSlot(i, added.stack); + break; + } + } + + if (dirty) { + markDirty(); + sendData(); + } + } + + public boolean isOutputEmpty() { + for (int i = 0; i < processingOutputBuffer.getSlots(); i++) + if (!processingOutputBuffer.getStackInSlot(i).isEmpty()) + return false; + return true; + } + + private Vec3d getWorldPositionOf(TransportedItemStack transported) { + Vec3d offsetVec = new Vec3d(.5f, 14 / 16f, .5f); + return offsetVec.add(new Vec3d(pos)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java index e6088f5b9..b99794025 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java @@ -138,7 +138,7 @@ public class FunnelBlock extends AttachedLogisticalBlock if (controllerBelt == null) return; - controllerBelt.getInventory().forEachWithin(belt.index + .5f, .55f, (transportedItemStack) -> { + controllerBelt.getInventory().applyToEachWithin(belt.index + .5f, .55f, (transportedItemStack) -> { controllerBelt.getInventory().eject(transportedItemStack); return Collections.emptyList(); }); diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java index 481e064f6..c6aa76d99 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java @@ -7,7 +7,7 @@ import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.ILightReader; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; public abstract class TileEntityBehaviour { @@ -90,12 +90,12 @@ public abstract class TileEntityBehaviour { return tileEntity.getWorld(); } - public static T get(ILightReader reader, BlockPos pos, + public static T get(IBlockReader reader, BlockPos pos, BehaviourType type) { return get(reader.getTileEntity(pos), type); } - public static void destroy(ILightReader reader, BlockPos pos, + public static void destroy(IBlockReader reader, BlockPos pos, BehaviourType type) { T behaviour = get(reader.getTileEntity(pos), type); if (behaviour != null) diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/BeltProcessingBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/BeltProcessingBehaviour.java index 2b64f01d9..2cb4f867a 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/BeltProcessingBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/BeltProcessingBehaviour.java @@ -1,15 +1,17 @@ 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; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; + /** - * 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 + * 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 { @@ -18,7 +20,7 @@ public class BeltProcessingBehaviour extends TileEntityBehaviour { public static enum ProcessingResult { PASS, HOLD, REMOVE; } - + private ProcessingCallback onItemEnter; private ProcessingCallback continueProcessing; @@ -27,33 +29,40 @@ public class BeltProcessingBehaviour extends TileEntityBehaviour { 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; } + public static boolean isBlocked(IBlockReader world, BlockPos processingSpace) { + return !world.getBlockState(processingSpace.up()) + .getCollisionShape(world, processingSpace.up()) + .isEmpty(); + } + @Override public BehaviourType getType() { return TYPE; } - public ProcessingResult handleReceivedItem(TransportedItemStack stack, BeltInventory inventory) { + public ProcessingResult handleReceivedItem(TransportedItemStack stack, + TransportedItemStackHandlerBehaviour inventory) { return onItemEnter.apply(stack, inventory); } - public ProcessingResult handleHeldItem(TransportedItemStack stack, BeltInventory inventory) { + public ProcessingResult handleHeldItem(TransportedItemStack stack, TransportedItemStackHandlerBehaviour inventory) { return continueProcessing.apply(stack, inventory); } @FunctionalInterface public interface ProcessingCallback { - public ProcessingResult apply(TransportedItemStack stack, BeltInventory inventory); + public ProcessingResult apply(TransportedItemStack stack, TransportedItemStackHandlerBehaviour inventory); } } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java new file mode 100644 index 000000000..d6484749c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java @@ -0,0 +1,54 @@ +package com.simibubi.create.foundation.tileEntity.behaviour.belt; + +import java.util.List; +import java.util.function.Function; + +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 com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.util.math.Vec3d; + +public class TransportedItemStackHandlerBehaviour extends TileEntityBehaviour { + + public static BehaviourType TYPE = new BehaviourType<>(); + private ProcessingCallback processingCallback; + private PositionGetter positionGetter; + + public TransportedItemStackHandlerBehaviour(SmartTileEntity te, ProcessingCallback processingCallback) { + super(te); + this.processingCallback = processingCallback; + positionGetter = t -> VecHelper.getCenterOf(te.getPos()); + } + + public TransportedItemStackHandlerBehaviour withStackPlacement(PositionGetter function) { + this.positionGetter = function; + return this; + } + + public void handleProcessingOnAllItems(Function> processFunction) { + this.processingCallback.applyToAllItems(processFunction); + } + + public Vec3d getWorldPositionOf(TransportedItemStack transported) { + return positionGetter.getWorldPositionVector(transported); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + @FunctionalInterface + public interface ProcessingCallback { + public void applyToAllItems(Function> processFunction); + } + + @FunctionalInterface + public interface PositionGetter { + public Vec3d getWorldPositionVector(TransportedItemStack transported); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java index 86a15ee16..bf6fe0122 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java @@ -10,7 +10,7 @@ import net.minecraft.util.math.BlockPos; public class Iterate { public static final boolean[] trueAndFalse = { true, false }; - public static final int[] zeroAndOne = { 1, -1 }; + public static final int[] zeroAndOne = { 0, 1 }; public static final int[] positiveAndNegative = { 1, -1 }; public static final Direction[] directions = Direction.values(); public static final Direction[] horizontalDirections = getHorizontals();