The Transposer

- Added behaviours to the Transposer tileentity
- Created new Inserting Behaviour for item management
- Fixed extractors syncing with extractors attached to other inventories
This commit is contained in:
simibubi 2020-01-07 22:15:37 +01:00
parent c682247894
commit 7059cf2737
6 changed files with 53 additions and 243 deletions

View file

@ -8,8 +8,11 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
public class InsertingBehaviour extends InventoryManagementBehaviour {
@ -20,6 +23,15 @@ public class InsertingBehaviour extends InventoryManagementBehaviour {
super(te, attachments);
}
public ItemStack insert(ItemStack stack, boolean simulate) {
for (IItemHandler inv : getInventories()) {
stack = ItemHandlerHelper.insertItemStacked(inv, stack, simulate);
if (stack.isEmpty())
break;
}
return stack;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;

View file

@ -103,7 +103,8 @@ public class InventoryManagementBehaviour extends TileEntityBehaviour {
public static class Attachments {
public static final Supplier<List<Pair<BlockPos, Direction>>> toward(Supplier<Direction> facing) {
return () -> ImmutableList.of(Pair.of(new BlockPos(facing.get().getDirectionVec()), facing.get()));
return () -> ImmutableList
.of(Pair.of(new BlockPos(facing.get().getDirectionVec()), facing.get().getOpposite()));
};
}

View file

@ -57,6 +57,9 @@ public class SynchronizedExtraction {
continue;
if (!behaviour.shouldExtract.get())
continue;
if (!behaviour.inventories.keySet().stream()
.anyMatch(p -> p.getKey().add(behaviour.getPos()).equals(pos)))
continue;
list.add(behaviour);
}

View file

@ -1,224 +0,0 @@
package com.simibubi.create.modules.logistics.block;
import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.item.CardboardBoxItem;
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
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.World;
import net.minecraftforge.items.IItemHandler;
// Its like delegation but worse!
public interface IExtractor extends ITickableTileEntity, IInventoryManipulator {
public enum State {
WAITING_FOR_INVENTORY, WAITING_FOR_ENTITY, RUNNING, ON_COOLDOWN, LOCKED;
}
public State getState();
public void setState(State state);
public int tickCooldown();
@Override
default void tick() {
if (isFrozen())
return;
State state = getState();
if (state == State.LOCKED)
return;
if (state == State.ON_COOLDOWN || state == State.WAITING_FOR_INVENTORY) {
int cooldown = tickCooldown();
if (cooldown <= 0) {
setState(State.RUNNING);
if (!getInventory().isPresent())
findNewInventory();
}
return;
}
boolean hasSpace = hasSpaceForExtracting();
boolean hasInventory = getInventory().isPresent();
ItemStack toExtract = ItemStack.EMPTY;
if (hasSpace && hasInventory) {
toExtract = extract(true);
if (!matchesFilter(toExtract))
toExtract = ItemStack.EMPTY;
}
if (state == State.WAITING_FOR_ENTITY) {
if (hasSpace)
setState(State.RUNNING);
}
if (state == State.RUNNING) {
if (!hasSpace) {
setState(State.WAITING_FOR_ENTITY);
return;
}
if (!hasInventory || toExtract.isEmpty()) {
setState(State.WAITING_FOR_INVENTORY);
return;
}
extract(false);
setState(State.ON_COOLDOWN);
return;
}
}
default boolean matchesFilter(ItemStack stack) {
FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get((TileEntity) this, FilteringBehaviour.TYPE);
return filteringBehaviour == null || filteringBehaviour.test(stack);
}
public default void setLocked(boolean locked) {
setState(locked ? State.LOCKED : State.ON_COOLDOWN);
}
public default void neighborChanged() {
if (isFrozen())
return;
boolean hasSpace = hasSpaceForExtracting();
boolean hasInventory = getInventory().isPresent();
ItemStack toExtract = ItemStack.EMPTY;
if (hasSpace && hasInventory) {
toExtract = extract(true);
if (!matchesFilter(toExtract))
toExtract = ItemStack.EMPTY;
}
if (getState() == State.WAITING_FOR_INVENTORY) {
if (!hasInventory) {
if (findNewInventory()) {
setState(State.RUNNING);
}
}
if (!toExtract.isEmpty())
setState(State.RUNNING);
return;
}
}
default boolean hasSpaceForExtracting() {
BlockPos pos = getPos();
World world = getWorld();
if (AllBlocks.BELT.typeOf(world.getBlockState(pos.down()))) {
TileEntity te = world.getTileEntity(pos.down());
if (te != null && te instanceof BeltTileEntity) {
BeltTileEntity belt = (BeltTileEntity) te;
BeltTileEntity controller = belt.getControllerTE();
if (controller != null) {
if (!controller.getInventory().canInsertFrom(belt.index, Direction.UP))
return false;
}
}
}
return world.getEntitiesWithinAABBExcludingEntity(null, new AxisAlignedBB(getPos())).isEmpty();
}
default ItemStack extract(boolean simulate) {
IItemHandler inv = getInventory().orElse(null);
ItemStack extracting = ItemStack.EMPTY;
FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get((TileEntity) this, FilteringBehaviour.TYPE);
ItemStack filterItem = filteringBehaviour == null ? ItemStack.EMPTY : filteringBehaviour.getFilter();
World world = getWorld();
int extractionCount = filterItem.isEmpty() ? CreateConfig.parameters.extractorAmount.get()
: filterItem.getCount();
boolean checkHasEnoughItems = !filterItem.isEmpty();
boolean hasEnoughItems = !checkHasEnoughItems;
Extraction: do {
extracting = ItemStack.EMPTY;
for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stack = inv.extractItem(slot, extractionCount - extracting.getCount(), true);
ItemStack compare = stack.copy();
compare.setCount(filterItem.getCount());
if (!filterItem.isEmpty() && !filterItem.equals(compare, false))
continue;
compare.setCount(extracting.getCount());
if (!extracting.isEmpty() && !extracting.equals(compare, false))
continue;
if (extracting.isEmpty())
extracting = stack.copy();
else
extracting.grow(stack.getCount());
if (!simulate && hasEnoughItems)
inv.extractItem(slot, stack.getCount(), false);
if (extracting.getCount() >= extractionCount) {
if (checkHasEnoughItems) {
hasEnoughItems = true;
checkHasEnoughItems = false;
continue Extraction;
} else {
break Extraction;
}
}
}
if (checkHasEnoughItems)
checkHasEnoughItems = false;
else
break Extraction;
} while (true);
if (!simulate && hasEnoughItems) {
Vec3d entityPos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0);
Entity entityIn = null;
if (extracting.getItem() instanceof CardboardBoxItem) {
Direction face = getWorld().getBlockState(getPos()).get(HORIZONTAL_FACING).getOpposite();
entityIn = new CardboardBoxEntity(world, entityPos, extracting, face);
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .25f, .05f);
} else {
entityIn = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, extracting);
entityIn.setMotion(Vec3d.ZERO);
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, .1f);
}
world.addEntity(entityIn);
}
return extracting;
}
public static boolean isFrozen() {
return CreateConfig.parameters.freezeExtractors.get();
}
}

View file

@ -30,10 +30,10 @@ import net.minecraft.util.math.Vec3d;
public class ExtractorTileEntity extends SmartTileEntity {
private static FilteringBehaviour.SlotPositioning slots;
protected static FilteringBehaviour.SlotPositioning slots;
private ExtractingBehaviour extracting;
private FilteringBehaviour filtering;
protected ExtractingBehaviour extracting;
protected FilteringBehaviour filtering;
public ExtractorTileEntity() {
this(AllTileEntities.EXTRACTOR.type);
@ -59,7 +59,7 @@ public class ExtractorTileEntity extends SmartTileEntity {
behaviours.add(filtering);
}
private void onExtract(ItemStack stack) {
protected void onExtract(ItemStack stack) {
Vec3d entityPos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0);
Entity entityIn = null;
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState());
@ -88,7 +88,7 @@ public class ExtractorTileEntity extends SmartTileEntity {
}
private boolean canExtract() {
protected boolean canExtract() {
if (AllBlocks.BELT.typeOf(world.getBlockState(pos.down()))) {
TileEntity te = world.getTileEntity(pos.down());
if (te != null && te instanceof BeltTileEntity) {

View file

@ -3,19 +3,19 @@ package com.simibubi.create.modules.logistics.block.transposer;
import java.util.List;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour.SlotPositioning;
import com.simibubi.create.modules.logistics.block.extractor.ExtractorBlock;
import com.simibubi.create.foundation.behaviour.inventory.InsertingBehaviour;
import com.simibubi.create.foundation.behaviour.inventory.InventoryManagementBehaviour.Attachments;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisticalBlock;
import com.simibubi.create.modules.logistics.block.extractor.ExtractorTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.items.ItemHandlerHelper;
public class TransposerTileEntity extends SmartTileEntity {
public class TransposerTileEntity extends ExtractorTileEntity {
private static FilteringBehaviour.SlotPositioning slots;
private FilteringBehaviour filtering;
private InsertingBehaviour inserting;
public TransposerTileEntity() {
this(AllTileEntities.TRANSPOSER.type);
@ -27,15 +27,33 @@ public class TransposerTileEntity extends SmartTileEntity {
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
if (slots == null)
slots = new SlotPositioning(ExtractorBlock::getFilterSlotPosition, ExtractorBlock::getFilterSlotOrientation)
.scale(.4f);
filtering = new FilteringBehaviour(this).withCallback(this::filterChanged).withSlotPositioning(slots)
.showCount();
behaviours.add(filtering);
super.addBehaviours(behaviours);
inserting = new InsertingBehaviour(this,
Attachments.toward(() -> AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite()));
behaviours.add(inserting);
extracting.withSpecialFilter(this::shouldExtract);
}
public void filterChanged(ItemStack stack) {
}
protected boolean shouldExtract(ItemStack stack) {
if (filtering.getFilter().isEmpty())
return true;
return inserting.insert(stack, true).isEmpty();
}
@Override
protected boolean canExtract() {
return inserting.getInventory() != null;
}
@Override
protected void onExtract(ItemStack stack) {
ItemStack remainder = inserting.insert(stack, false);
remainder = ItemHandlerHelper.insertItemStacked(extracting.getInventory(), remainder, false);
if (!remainder.isEmpty())
super.onExtract(remainder);
}
}