ExtractionBehaviour and Synchronized Extractors

- Added Inventory Manipulation and Extraction Behaviours
- Extractors are now aware of other extractors on the same inventory and will take turns
This commit is contained in:
simibubi 2020-01-07 17:49:07 +01:00
parent 1a8fca038d
commit c682247894
21 changed files with 587 additions and 205 deletions

View file

@ -1,21 +0,0 @@
package com.simibubi.create.foundation.behaviour;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
public class LinkedBehaviour extends TileEntityBehaviour {
public static IBehaviourType<LinkedBehaviour> TYPE = new IBehaviourType<LinkedBehaviour>() {
};
public LinkedBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -12,10 +12,13 @@ public abstract class TileEntityBehaviour {
public SmartTileEntity tileEntity;
private boolean paused;
private int lazyTickRate;
private int lazyTickCounter;
public TileEntityBehaviour(SmartTileEntity te) {
tileEntity = te;
paused = false;
setLazyTickRate(10);
}
public abstract IBehaviourType<?> getType();
@ -25,7 +28,11 @@ public abstract class TileEntityBehaviour {
}
public void tick() {
if (lazyTickCounter-- <= 0) {
lazyTickCounter = lazyTickRate;
lazyTick();
}
}
public void readNBT(CompoundNBT nbt) {
@ -56,14 +63,23 @@ public abstract class TileEntityBehaviour {
return paused;
}
public void setLazyTickRate(int slowTickRate) {
this.lazyTickRate = slowTickRate;
this.lazyTickCounter = slowTickRate;
}
public void lazyTick() {
}
public void setPaused(boolean paused) {
this.paused = paused;
}
public BlockPos getPos() {
return tileEntity.getPos();
}
public World getWorld() {
return tileEntity.getWorld();
}

View file

@ -0,0 +1,80 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
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;
public class AutoExtractingBehaviour extends ExtractingBehaviour {
public static IBehaviourType<AutoExtractingBehaviour> TYPE = new IBehaviourType<AutoExtractingBehaviour>() {
};
private int delay;
private int timer;
Supplier<Boolean> shouldExtract;
Supplier<Boolean> shouldPause;
public AutoExtractingBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments,
Consumer<ItemStack> onExtract, int delay) {
super(te, attachments, onExtract);
shouldPause = () -> false;
shouldExtract = () -> true;
this.delay = delay;
}
public AutoExtractingBehaviour pauseWhen(Supplier<Boolean> condition) {
shouldPause = condition;
return this;
}
public ExtractingBehaviour waitUntil(Supplier<Boolean> condition) {
this.shouldExtract = condition;
return this;
}
public void setDelay(int delay) {
this.delay = delay;
this.timer = delay;
}
@Override
public boolean extract() {
timer = delay;
return super.extract();
}
@Override
public void tick() {
super.tick();
if (shouldPause.get()) {
timer = 0;
return;
}
if (timer > 0) {
timer--;
return;
}
if (!shouldExtract.get())
return;
extract();
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -0,0 +1,70 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.item.ItemHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandler;
public class ExtractingBehaviour extends InventoryManagementBehaviour {
public static IBehaviourType<ExtractingBehaviour> TYPE = new IBehaviourType<ExtractingBehaviour>() {
};
private Predicate<ItemStack> extractionFilter;
private Consumer<ItemStack> callback;
public ExtractingBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments,
Consumer<ItemStack> onExtract) {
super(te, attachments);
extractionFilter = stack -> true;
callback = onExtract;
}
public ExtractingBehaviour withSpecialFilter(Predicate<ItemStack> filter) {
this.extractionFilter = filter;
return this;
}
public boolean extract() {
if (getWorld().isRemote)
return false;
int amount = -1;
Predicate<ItemStack> test = extractionFilter;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null) {
ItemStack filterItem = filter.getFilter();
amount = filterItem.isEmpty() ? -1 : filterItem.getCount();
test = extractionFilter.and(filter::test);
}
for (IItemHandler inv : getInventories()) {
ItemStack extract = ItemHelper.extract(inv, test, amount, false);
if (!extract.isEmpty()) {
callback.accept(extract);
return true;
}
}
return false;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -0,0 +1,28 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.List;
import java.util.function.Supplier;
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.util.Direction;
import net.minecraft.util.math.BlockPos;
public class InsertingBehaviour extends InventoryManagementBehaviour {
public static IBehaviourType<InsertingBehaviour> TYPE = new IBehaviourType<InsertingBehaviour>() {
};
public InsertingBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments) {
super(te, attachments);
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -0,0 +1,110 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class InventoryManagementBehaviour extends TileEntityBehaviour {
Map<Pair<BlockPos, Direction>, LazyOptional<IItemHandler>> inventories;
private Supplier<List<Pair<BlockPos, Direction>>> attachments;
private List<IItemHandler> activeHandlers;
public static IBehaviourType<InventoryManagementBehaviour> TYPE = new IBehaviourType<InventoryManagementBehaviour>() {
};
public InventoryManagementBehaviour(SmartTileEntity te, Supplier<List<Pair<BlockPos, Direction>>> attachments) {
super(te);
this.attachments = attachments;
setLazyTickRate(20);
activeHandlers = new ArrayList<>();
inventories = new HashMap<>();
}
@Override
public void initialize() {
super.initialize();
attachments.get().forEach(offset -> inventories.put(offset, findInventory(offset)));
}
@Override
public void lazyTick() {
super.lazyTick();
activeHandlers.clear();
for (Pair<BlockPos, Direction> pair : inventories.keySet()) {
LazyOptional<IItemHandler> lazyOptional = inventories.get(pair);
if (lazyOptional.isPresent()) {
activeHandlers.add(lazyOptional.orElse(null));
continue;
}
lazyOptional = findInventory(pair);
if (lazyOptional.isPresent())
activeHandlers.add(lazyOptional.orElse(null));
inventories.put(pair, lazyOptional);
}
}
public List<IItemHandler> getInventories() {
return activeHandlers;
}
public IItemHandler getInventory() {
if (activeHandlers.isEmpty())
return null;
return activeHandlers.get(0);
}
protected LazyOptional<IItemHandler> findInventory(Pair<BlockPos, Direction> offset) {
BlockPos invPos = tileEntity.getPos().add(offset.getKey());
World world = getWorld();
if (!world.isBlockPresent(invPos))
return LazyOptional.empty();
BlockState invState = world.getBlockState(invPos);
if (!invState.hasTileEntity())
return LazyOptional.empty();
TileEntity invTE = world.getTileEntity(invPos);
if (invTE == null)
return LazyOptional.empty();
LazyOptional<IItemHandler> inventory = invTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
offset.getValue());
if (inventory == null) {
return LazyOptional.empty();
}
return inventory;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
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()));
};
}
}

View file

@ -0,0 +1,53 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.function.Consumer;
import java.util.function.Supplier;
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;
public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour {
public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE = new IBehaviourType<SingleTargetAutoExtractingBehaviour>() {
};
private Supplier<Direction> attachmentDirection;
boolean synced;
boolean advantageOnNextSync;
public SingleTargetAutoExtractingBehaviour(SmartTileEntity te, Supplier<Direction> attachmentDirection,
Consumer<ItemStack> onExtract, int delay) {
super(te, Attachments.toward(attachmentDirection), onExtract, delay);
this.attachmentDirection = attachmentDirection;
synced = true;
advantageOnNextSync = false;
}
public SingleTargetAutoExtractingBehaviour dontSynchronize() {
synced = false;
return this;
}
@Override
public boolean extract() {
if (synced) {
BlockPos invPos = tileEntity.getPos().offset(attachmentDirection.get());
return SynchronizedExtraction.extractSynchronized(getWorld(), invPos);
} else
return extractFromInventory();
}
public boolean extractFromInventory() {
return super.extract();
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -0,0 +1,67 @@
package com.simibubi.create.foundation.behaviour.inventory;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.block.ChestBlock;
import net.minecraft.state.properties.ChestType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IEnviromentBlockReader;
public class SynchronizedExtraction {
static boolean extractSynchronized(IEnviromentBlockReader reader, BlockPos inventoryPos) {
List<SingleTargetAutoExtractingBehaviour> actors = getAllSyncedExtractors(reader, inventoryPos);
int startIndex = actors.size() - 1;
boolean success = false;
for (; startIndex > 0; startIndex--)
if (actors.get(startIndex).advantageOnNextSync)
break;
for (int i = 0; i < actors.size(); i++)
success |= actors.get((startIndex + i) % actors.size()).extractFromInventory();
if (success) {
actors.get(startIndex).advantageOnNextSync = false;
actors.get((startIndex + 1) % actors.size()).advantageOnNextSync = true;
}
return success;
}
private static List<SingleTargetAutoExtractingBehaviour> getAllSyncedExtractors(IEnviromentBlockReader reader,
BlockPos inventoryPos) {
List<SingleTargetAutoExtractingBehaviour> list = new ArrayList<>();
List<BlockPos> inventoryPositions = new ArrayList<>();
inventoryPositions.add(inventoryPos);
// Sync across double chests
BlockState blockState = reader.getBlockState(inventoryPos);
if (blockState.getBlock() instanceof ChestBlock)
if (blockState.get(ChestBlock.TYPE) != ChestType.SINGLE)
inventoryPositions.add(inventoryPos.offset(ChestBlock.getDirectionToAttached(blockState)));
for (BlockPos pos : inventoryPositions) {
for (Direction direction : Direction.values()) {
SingleTargetAutoExtractingBehaviour behaviour = TileEntityBehaviour.get(reader, pos.offset(direction),
SingleTargetAutoExtractingBehaviour.TYPE);
if (behaviour == null)
continue;
if (!behaviour.synced)
continue;
if (behaviour.shouldPause.get())
continue;
if (!behaviour.shouldExtract.get())
continue;
list.add(behaviour);
}
}
return list;
}
}

View file

@ -2,10 +2,13 @@ package com.simibubi.create.foundation.item;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.CreateConfig;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
@ -85,4 +88,57 @@ public class ItemHelper {
return false;
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, boolean simulate) {
return extract(inv, test, -1, simulate);
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, int exactAmount, boolean simulate) {
ItemStack extracting = ItemStack.EMPTY;
boolean amountRequired = exactAmount != -1;
boolean checkHasEnoughItems = amountRequired;
boolean hasEnoughItems = !checkHasEnoughItems;
int maxExtractionCount = hasEnoughItems ? CreateConfig.parameters.extractorAmount.get() : exactAmount;
Extraction: do {
extracting = ItemStack.EMPTY;
for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stack = inv.extractItem(slot, maxExtractionCount - extracting.getCount(), true);
if (!test.test(stack))
continue;
if (!extracting.isEmpty() && !ItemHandlerHelper.canItemStacksStack(stack, extracting))
continue;
if (extracting.isEmpty())
extracting = stack.copy();
else
extracting.grow(stack.getCount());
if (!simulate && hasEnoughItems)
inv.extractItem(slot, stack.getCount(), false);
if (extracting.getCount() >= maxExtractionCount) {
if (checkHasEnoughItems) {
hasEnoughItems = true;
checkHasEnoughItems = false;
continue Extraction;
} else {
break Extraction;
}
}
}
if (checkHasEnoughItems)
checkHasEnoughItems = false;
else
break Extraction;
} while (true);
if (amountRequired && extracting.getCount() < exactAmount)
return ItemStack.EMPTY;
return extracting;
}
}

View file

@ -25,7 +25,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
// Its like delegation but better!
// Its like delegation but worse!
public interface IExtractor extends ITickableTileEntity, IInventoryManipulator {
public enum State {

View file

@ -18,11 +18,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public abstract class AttachedLogisiticalBlock extends HorizontalBlock implements IHaveNoBlockItem {
public abstract class AttachedLogisticalBlock extends HorizontalBlock implements IHaveNoBlockItem {
public static final BooleanProperty UPWARD = BooleanProperty.create("upward");
public AttachedLogisiticalBlock() {
public AttachedLogisticalBlock() {
super(Properties.from(Blocks.ANDESITE));
}
@ -97,8 +97,8 @@ public abstract class AttachedLogisiticalBlock extends HorizontalBlock implement
public static boolean isVertical(BlockState state) {
Block block = state.getBlock();
return ((block instanceof AttachedLogisiticalBlock)
&& (((AttachedLogisiticalBlock) state.getBlock())).isVertical());
return ((block instanceof AttachedLogisticalBlock)
&& (((AttachedLogisticalBlock) state.getBlock())).isVertical());
}
@Override

View file

@ -29,7 +29,7 @@ import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class FunnelBlock extends AttachedLogisiticalBlock
public class FunnelBlock extends AttachedLogisticalBlock
implements IBeltAttachment, IWithTileEntity<FunnelTileEntity> {
public static final BooleanProperty BELT = BooleanProperty.create("belt");
@ -61,18 +61,6 @@ public class FunnelBlock extends AttachedLogisiticalBlock
return AllBlocks.VERTICAL_FUNNEL.getDefault();
}
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
Direction blockFacing = state.get(HORIZONTAL_FACING);
if (fromPos.equals(pos.offset(blockFacing))) {
if (!isValidPosition(state, worldIn, pos)) {
worldIn.destroyBlock(pos, true);
return;
}
}
}
@Override
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn,
BlockPos currentPos, BlockPos facingPos) {

View file

@ -165,16 +165,16 @@ public class FunnelTileEntity extends SmartTileEntity implements ITickableTileEn
Vec3d vec = offsetForHorizontal;
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
if (AttachedLogisiticalBlock.isVertical(state))
vec = state.get(AttachedLogisiticalBlock.UPWARD) ? offsetForUpward : offsetForDownward;
if (AttachedLogisticalBlock.isVertical(state))
vec = state.get(AttachedLogisticalBlock.UPWARD) ? offsetForUpward : offsetForDownward;
else if (state.get(FunnelBlock.BELT))
vec = offsetForBelt;
return VecHelper.rotateCentered(vec, yRot, Axis.Y);
}, state -> {
Direction blockFacing = AttachedLogisiticalBlock.getBlockFacing(state);
boolean vertical = AttachedLogisiticalBlock.isVertical(state);
Direction blockFacing = AttachedLogisticalBlock.getBlockFacing(state);
boolean vertical = AttachedLogisticalBlock.isVertical(state);
float horizontalAngle = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
float yRot = blockFacing == Direction.DOWN ? horizontalAngle + 180 : horizontalAngle;

View file

@ -4,8 +4,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.logistics.block.IExtractor;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisiticalBlock;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisticalBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -20,10 +19,9 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class ExtractorBlock extends AttachedLogisiticalBlock {
public class ExtractorBlock extends AttachedLogisticalBlock {
public static BooleanProperty POWERED = BlockStateProperties.POWERED;
@ -63,31 +61,6 @@ public class ExtractorBlock extends AttachedLogisiticalBlock {
reactsToRedstone() && context.getWorld().isBlockPowered(context.getPos()));
}
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
updateObservedInventory(state, worldIn, pos);
}
@Override
public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) {
if (world.isRemote())
return;
if (!isObserving(state, pos, neighbor))
return;
updateObservedInventory(state, world, pos);
}
private void updateObservedInventory(BlockState state, IWorldReader world, BlockPos pos) {
IExtractor extractor = (IExtractor) world.getTileEntity(pos);
if (extractor == null)
return;
extractor.neighborChanged();
}
private boolean isObserving(BlockState state, BlockPos pos, BlockPos observing) {
return observing.equals(pos.offset(getBlockFacing(state)));
}
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
@ -99,13 +72,8 @@ public class ExtractorBlock extends AttachedLogisiticalBlock {
return;
boolean previouslyPowered = state.get(POWERED);
if (previouslyPowered != worldIn.isBlockPowered(pos)) {
if (previouslyPowered != worldIn.isBlockPowered(pos))
worldIn.setBlockState(pos, state.cycle(POWERED), 2);
IExtractor extractor = (IExtractor) worldIn.getTileEntity(pos);
if (extractor == null)
return;
extractor.setLocked(!previouslyPowered);
}
}
protected boolean reactsToRedstone() {
@ -119,22 +87,22 @@ public class ExtractorBlock extends AttachedLogisiticalBlock {
public static Vec3d getFilterSlotPosition(BlockState state) {
float verticalOffset = (state.getBlock() instanceof ExtractorBlock) ? 10.5f : 12.5f;
Vec3d offsetForHorizontal = VecHelper.voxelSpace(8f, verticalOffset, 14f);
Vec3d offsetForUpward = VecHelper.voxelSpace(8f, 14.15f, 3.5f);
Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 1.85f, 3.5f);
Vec3d vec = offsetForHorizontal;
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
if (AttachedLogisiticalBlock.isVertical(state))
vec = state.get(AttachedLogisiticalBlock.UPWARD) ? offsetForUpward : offsetForDownward;
if (AttachedLogisticalBlock.isVertical(state))
vec = state.get(AttachedLogisticalBlock.UPWARD) ? offsetForUpward : offsetForDownward;
return VecHelper.rotateCentered(vec, yRot, Axis.Y);
}
public static Vec3d getFilterSlotOrientation(BlockState state) {
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
float zRot = (AttachedLogisiticalBlock.isVertical(state)) ? 0 : 90;
float zRot = (AttachedLogisticalBlock.isVertical(state)) ? 0 : 90;
return new Vec3d(0, yRot, zRot);
}

View file

@ -2,32 +2,37 @@ package com.simibubi.create.modules.logistics.block.extractor;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.CreateConfig;
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.IExtractor;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisiticalBlock;
import com.simibubi.create.foundation.behaviour.inventory.ExtractingBehaviour;
import com.simibubi.create.foundation.behaviour.inventory.SingleTargetAutoExtractingBehaviour;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisticalBlock;
import com.simibubi.create.modules.logistics.item.CardboardBoxItem;
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
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.Vec3d;
public class ExtractorTileEntity extends SmartTileEntity implements IExtractor, ITickableTileEntity {
public class ExtractorTileEntity extends SmartTileEntity {
private static FilteringBehaviour.SlotPositioning slots;
private State state;
private int cooldown;
private LazyOptional<IItemHandler> inventory;
private ExtractingBehaviour extracting;
private FilteringBehaviour filtering;
public ExtractorTileEntity() {
@ -36,13 +41,16 @@ public class ExtractorTileEntity extends SmartTileEntity implements IExtractor,
protected ExtractorTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
state = State.ON_COOLDOWN;
cooldown = CreateConfig.parameters.extractorDelay.get();
inventory = LazyOptional.empty();
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
int delay = CreateConfig.parameters.extractorDelay.get();
extracting = new SingleTargetAutoExtractingBehaviour(this,
() -> AttachedLogisticalBlock.getBlockFacing(getBlockState()), this::onExtract, delay)
.pauseWhen(this::isPowered).waitUntil(this::canExtract);
behaviours.add(extracting);
if (slots == null)
slots = new SlotPositioning(ExtractorBlock::getFilterSlotPosition, ExtractorBlock::getFilterSlotOrientation)
.scale(.4f);
@ -51,73 +59,49 @@ public class ExtractorTileEntity extends SmartTileEntity implements IExtractor,
behaviours.add(filtering);
}
public void filterChanged(ItemStack stack) {
neighborChanged();
private void onExtract(ItemStack stack) {
Vec3d entityPos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0);
Entity entityIn = null;
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState());
if (facing == Direction.DOWN)
entityPos = entityPos.add(0, .5, 0);
if (stack.getItem() instanceof CardboardBoxItem) {
entityIn = new CardboardBoxEntity(world, entityPos, stack, facing.getOpposite());
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .25f, .05f);
} else {
entityIn = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, stack);
entityIn.setMotion(Vec3d.ZERO);
((ItemEntity) entityIn).setPickupDelay(5);
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, .1f);
}
world.addEntity(entityIn);
}
@Override
public State getState() {
return state;
protected boolean isPowered() {
return getBlockState().get(ExtractorBlock.POWERED);
}
@Override
public void read(CompoundNBT compound) {
if (compound.getBoolean("Locked"))
setState(State.LOCKED);
super.read(compound);
private void filterChanged(ItemStack stack) {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.putBoolean("Locked", getState() == State.LOCKED);
return super.write(compound);
}
private boolean canExtract() {
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;
}
}
}
@Override
public void initialize() {
super.initialize();
if (world.isBlockPowered(pos))
state = State.LOCKED;
neighborChanged();
}
@Override
public void tick() {
super.tick();
IExtractor.super.tick();
}
@Override
public void setState(State state) {
if (state == State.ON_COOLDOWN)
cooldown = CreateConfig.parameters.extractorDelay.get();
if (state == State.WAITING_FOR_INVENTORY)
cooldown = CreateConfig.parameters.extractorInventoryScanDelay.get();
this.state = state;
}
@Override
public int tickCooldown() {
return cooldown--;
}
@Override
public BlockPos getInventoryPos() {
BlockState blockState = getBlockState();
Block block = blockState.getBlock();
if (!(block instanceof ExtractorBlock))
return null;
return getPos().offset(AttachedLogisiticalBlock.getBlockFacing(blockState));
}
@Override
public LazyOptional<IItemHandler> getInventory() {
return inventory;
}
@Override
public void setInventory(LazyOptional<IItemHandler> inventory) {
this.inventory = inventory;
return world.getEntitiesWithinAABBExcludingEntity(null, new AxisAlignedBB(getPos())).isEmpty();
}
}

View file

@ -5,7 +5,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisiticalBlock;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisticalBlock;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
@ -48,8 +48,8 @@ public class LinkedExtractorBlock extends ExtractorBlock {
Vec3d secondDownward = VecHelper.voxelSpace(6f, 2f, 11.5f);
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
if (AttachedLogisiticalBlock.isVertical(state)) {
Boolean up = state.get(AttachedLogisiticalBlock.UPWARD);
if (AttachedLogisticalBlock.isVertical(state)) {
Boolean up = state.get(AttachedLogisticalBlock.UPWARD);
first = up ? firstUpward : firstDownward;
second = up ? secondUpward : secondDownward;
}
@ -60,7 +60,7 @@ public class LinkedExtractorBlock extends ExtractorBlock {
}
public static Vec3d getFrequencySlotOrientation(BlockState state) {
boolean vertical = AttachedLogisiticalBlock.isVertical(state);
boolean vertical = AttachedLogisticalBlock.isVertical(state);
float horizontalAngle = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
float xRot = vertical ? (state.get(UPWARD) ? 90 : 270) : 0;

View file

@ -8,11 +8,6 @@ import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.linked.LinkBehaviour;
import com.simibubi.create.foundation.behaviour.linked.LinkBehaviour.SlotPositioning;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisiticalBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
public class LinkedExtractorTileEntity extends ExtractorTileEntity {
@ -38,33 +33,13 @@ public class LinkedExtractorTileEntity extends ExtractorTileEntity {
receivedSignal = powered;
}
@Override
public void initialize() {
super.initialize();
if (world.isBlockPowered(pos))
setState(State.LOCKED);
neighborChanged();
}
@Override
public void tick() {
super.tick();
if (world.isRemote)
return;
if (receivedSignal != getBlockState().get(POWERED)) {
setLocked(receivedSignal);
if (receivedSignal != getBlockState().get(POWERED))
world.setBlockState(pos, getBlockState().cycle(POWERED));
return;
}
}
@Override
public BlockPos getInventoryPos() {
BlockState blockState = getBlockState();
Block block = blockState.getBlock();
if (!(block instanceof ExtractorBlock))
return null;
return getPos().offset(AttachedLogisiticalBlock.getBlockFacing(blockState));
}
}

View file

@ -2,7 +2,7 @@ package com.simibubi.create.modules.logistics.block.transposer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisiticalBlock;
import com.simibubi.create.modules.logistics.block.belts.AttachedLogisticalBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -19,19 +19,19 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class TransposerBlock extends AttachedLogisiticalBlock {
public class TransposerBlock extends AttachedLogisticalBlock {
public static BooleanProperty POWERED = BlockStateProperties.POWERED;
public TransposerBlock() {
setDefaultState(getDefaultState().with(POWERED, false));
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new TransposerTileEntity();
@ -66,10 +66,17 @@ public class TransposerBlock extends AttachedLogisiticalBlock {
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving);
if (worldIn.isRemote)
return;
Direction blockFacing = getBlockFacing(state);
if (fromPos.equals(pos.offset(blockFacing)) || fromPos.equals(pos.offset(blockFacing.getOpposite()))) {
if (!isValidPosition(state, worldIn, pos)) {
worldIn.destroyBlock(pos, true);
return;
}
}
if (!reactsToRedstone())
return;

View file

@ -2,7 +2,8 @@
"parent": "block/block",
"textures": {
"particle": "create:block/flex_crate",
"flex_crate": "create:block/flex_crate"
"side": "create:block/flex_crate",
"top": "create:block/brass_casing_14"
},
"elements": [
{
@ -10,12 +11,12 @@
"from": [ 1, 0, 1 ],
"to": [ 15, 14, 15 ],
"faces": {
"north": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] },
"east": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] },
"south": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] },
"west": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] },
"up": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] },
"down": { "texture": "#flex_crate", "uv": [ 1, 1, 15, 15 ] }
"north": { "texture": "#side", "uv": [ 1, 1, 15, 15 ] },
"east": { "texture": "#side", "uv": [ 1, 1, 15, 15 ] },
"south": { "texture": "#side", "uv": [ 1, 1, 15, 15 ] },
"west": { "texture": "#side", "uv": [ 1, 1, 15, 15 ] },
"up": { "texture": "#top", "uv": [ 1, 1, 15, 15 ] },
"down": { "texture": "#top", "uv": [ 1, 1, 15, 15 ] }
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 580 B