Portable Storage Interface remaster

- Implemented new PSI models by Kryppers
- PSIs are now used in pairs like contacts
- PSIs now act as an inventory proxy of the attached contraption
- Comparators can detect when two PSIs are interfacing
- Contraptions will continue moving after a second of inactivity
This commit is contained in:
simibubi 2020-09-24 20:32:16 +02:00
parent 2d6d360da4
commit 27b05bc43e
8 changed files with 362 additions and 145 deletions

View file

@ -4,6 +4,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
@ -14,10 +15,12 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
public class PortableStorageInterfaceBlock extends ProperDirectionalBlock { public class PortableStorageInterfaceBlock extends ProperDirectionalBlock
implements ITE<PortableStorageInterfaceTileEntity> {
public PortableStorageInterfaceBlock(Properties p_i48415_1_) { public PortableStorageInterfaceBlock(Properties p_i48415_1_) {
super(p_i48415_1_); super(p_i48415_1_);
@ -44,4 +47,23 @@ public class PortableStorageInterfaceBlock extends ProperDirectionalBlock {
return AllShapes.PORTABLE_STORAGE_INTERFACE.get(state.get(FACING)); return AllShapes.PORTABLE_STORAGE_INTERFACE.get(state.get(FACING));
} }
@Override
public boolean hasComparatorInputOverride(BlockState state) {
return true;
}
@Override
public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) {
try {
return getTileEntity(worldIn, pos).isConnected() ? 15 : 0;
} catch (TileEntityException e) {
}
return 0;
}
@Override
public Class<PortableStorageInterfaceTileEntity> getTileEntityClass() {
return PortableStorageInterfaceTileEntity.class;
}
} }

View file

@ -1,133 +1,104 @@
package com.simibubi.create.content.contraptions.components.actors; package com.simibubi.create.content.contraptions.components.actors;
import java.util.function.Predicate; import java.util.Optional;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.SingleTargetAutoExtractingBehaviour;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.api.distmarker.OnlyIn;
public class PortableStorageInterfaceMovement extends MovementBehaviour { public class PortableStorageInterfaceMovement extends MovementBehaviour {
private static final String _exporting_ = "Exporting"; static final String _workingPos_ = "WorkingPos";
private static final String _delay_ = "Delay"; static final String _clientPrevPos_ = "ClientPrevPos";
private static final String _workingPos_ = "WorkingPos";
@Override @Override
public Vec3d getActiveAreaOffset(MovementContext context) { public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING) return new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING)
.getDirectionVec()).scale(.85f); .getDirectionVec()).scale(1.85f);
}
@Override
@OnlyIn(Dist.CLIENT)
public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal,
IRenderTypeBuffer buffer) {
PortableStorageInterfaceRenderer.renderInContraption(context, ms, msLocal, buffer);
} }
@Override @Override
public void visitNewPosition(MovementContext context, BlockPos pos) { public void visitNewPosition(MovementContext context, BlockPos pos) {
Direction currentFacing = getCurrentFacing(context); context.data.remove(_workingPos_);
PortableStorageInterfaceTileEntity psi = if (findInterface(context, pos))
getValidStationaryInterface(context.world, pos, currentFacing.getAxis());
if (psi == null)
return;
if (psi.isTransferring())
return;
context.data.put(_workingPos_, NBTUtil.writeBlockPos(pos));
context.stall = true; context.stall = true;
} }
protected boolean findInterface(MovementContext context, BlockPos pos) {
Optional<Direction> currentFacingIfValid = getCurrentFacingIfValid(context);
if (!currentFacingIfValid.isPresent())
return false;
Direction currentFacing = currentFacingIfValid.get();
PortableStorageInterfaceTileEntity psi = findStationaryInterface(context.world, pos, currentFacing);
if (psi == null)
return false;
if (psi.isTransferring() && !context.world.isRemote)
return false;
context.data.put(_workingPos_, NBTUtil.writeBlockPos(psi.getPos()));
if (!context.world.isRemote) {
Vec3d diff = VecHelper.getCenterOf(psi.getPos())
.subtract(context.position);
diff = VecHelper.project(diff, new Vec3d(currentFacing.getDirectionVec()));
float distance = (float) (diff.length() + 1.85f - 1);
psi.startTransferringTo(context.contraption, distance);
} else {
context.data.put(_clientPrevPos_, NBTUtil.writeBlockPos(pos));
}
return true;
}
@Override @Override
public void tick(MovementContext context) { public void tick(MovementContext context) {
if (!context.data.contains(_workingPos_)) if (context.world.isRemote) {
boolean stalled = context.contraption.stalled;
if (stalled && !context.data.contains(_workingPos_)) {
BlockPos pos = new BlockPos(context.position);
if (!context.data.contains(_clientPrevPos_)
|| !NBTUtil.readBlockPos(context.data.getCompound(_clientPrevPos_))
.equals(pos))
findInterface(context, pos);
}
if (!stalled)
reset(context);
return; return;
if (context.world.isRemote) }
if (!context.data.contains(_workingPos_))
return; return;
BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_)); BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_));
Optional<Direction> currentFacingIfValid = getCurrentFacingIfValid(context);
if (!currentFacingIfValid.isPresent())
return;
PortableStorageInterfaceTileEntity stationaryInterface = PortableStorageInterfaceTileEntity stationaryInterface =
getValidStationaryInterface(context.world, pos, getCurrentFacing(context).getAxis()); getStationaryInterfaceAt(context.world, pos, currentFacingIfValid.get());
if (stationaryInterface == null) { if (stationaryInterface == null || !stationaryInterface.isTransferring()) {
reset(context); reset(context);
return; return;
} }
int nextExtract = context.data.getInt(_delay_);
if (nextExtract > 0) {
nextExtract--;
context.data.putInt(_delay_, nextExtract);
return;
}
boolean extract = context.data.getBoolean(_exporting_);
boolean success = false;
IItemHandlerModifiable inv = context.contraption.inventory;
SingleTargetAutoExtractingBehaviour extracting =
TileEntityBehaviour.get(stationaryInterface, SingleTargetAutoExtractingBehaviour.TYPE);
FilteringBehaviour filtering = TileEntityBehaviour.get(stationaryInterface, FilteringBehaviour.TYPE);
if (extract) {
// Export from Contraption
Predicate<ItemStack> test = extracting.getFilterTest();
int exactAmount = extracting.getAmountFromFilter();
ItemStack itemExtracted = ItemStack.EMPTY;
if (exactAmount != -1)
itemExtracted = ItemHelper.extract(inv, test, exactAmount, false);
else
itemExtracted = ItemHelper.extract(inv, test, stationaryInterface::amountToExtract, false);
if (!itemExtracted.isEmpty()) {
stationaryInterface.onExtract(itemExtracted);
success = exactAmount == -1;
}
} else {
// Import to Contraption
if (extracting != null) {
extracting.setSynchronized(false);
extracting.withAdditionalFilter(stack -> {
if (filtering.anyAmount())
return true;
return ItemHandlerHelper.insertItemStacked(inv, stack, true)
.isEmpty();
});
extracting.withAmountThreshold(stack -> {
ItemStack tester = stack.copy();
tester.setCount(tester.getMaxStackSize());
return stack.getCount() - ItemHandlerHelper.insertItemStacked(inv, stack, true)
.getCount();
});
extracting.setCallback(stack -> {
ItemHandlerHelper.insertItemStacked(inv, stack, false);
});
success = extracting.extract() && filtering.anyAmount();
extracting.setSynchronized(true);
stationaryInterface.applyFilteringCallbacks();
extracting.setCallback(stationaryInterface::onExtract);
}
}
if (!success) {
reset(context);
return;
}
context.data.putInt(_delay_, AllConfigs.SERVER.logistics.defaultExtractionTimer.get());
} }
@Override @Override
@ -136,32 +107,42 @@ public class PortableStorageInterfaceMovement extends MovementBehaviour {
} }
public void reset(MovementContext context) { public void reset(MovementContext context) {
context.data.remove(_clientPrevPos_);
context.data.remove(_workingPos_); context.data.remove(_workingPos_);
context.data.remove(_delay_);
context.data.remove(_exporting_);
context.stall = false; context.stall = false;
} }
private PortableStorageInterfaceTileEntity getValidStationaryInterface(World world, BlockPos pos, Axis validAxis) { private PortableStorageInterfaceTileEntity findStationaryInterface(World world, BlockPos pos, Direction facing) {
for (int i = 0; i < 2; i++) {
PortableStorageInterfaceTileEntity interfaceAt =
getStationaryInterfaceAt(world, pos.offset(facing, i), facing);
if (interfaceAt == null)
continue;
return interfaceAt;
}
return null;
}
private PortableStorageInterfaceTileEntity getStationaryInterfaceAt(World world, BlockPos pos, Direction facing) {
TileEntity te = world.getTileEntity(pos); TileEntity te = world.getTileEntity(pos);
if (!(te instanceof PortableStorageInterfaceTileEntity)) if (!(te instanceof PortableStorageInterfaceTileEntity))
return null; return null;
BlockState blockState = world.getBlockState(pos); BlockState blockState = world.getBlockState(pos);
if (!AllBlocks.PORTABLE_STORAGE_INTERFACE.has(blockState)) if (!AllBlocks.PORTABLE_STORAGE_INTERFACE.has(blockState))
return null; return null;
if (blockState.get(PortableStorageInterfaceBlock.FACING) if (blockState.get(PortableStorageInterfaceBlock.FACING) != facing.getOpposite())
.getAxis() != validAxis)
return null;
if (world.isBlockPowered(pos))
return null; return null;
return (PortableStorageInterfaceTileEntity) te; return (PortableStorageInterfaceTileEntity) te;
} }
private Direction getCurrentFacing(MovementContext context) { private Optional<Direction> getCurrentFacingIfValid(MovementContext context) {
Vec3d directionVec = new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING) Vec3d directionVec = new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING)
.getDirectionVec()); .getDirectionVec());
directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z); directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z);
return Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z); Direction facingFromVector = Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z);
if (directionVec.distanceTo(new Vec3d(facingFromVector.getDirectionVec())) > 1 / 8f)
return Optional.empty();
return Optional.of(facingFromVector);
} }
} }

View file

@ -1,20 +1,25 @@
package com.simibubi.create.content.contraptions.components.actors; package com.simibubi.create.content.contraptions.components.actors;
import java.util.function.Consumer;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.BlockPos;
public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer<PortableStorageInterfaceTileEntity> { public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer<PortableStorageInterfaceTileEntity> {
@ -25,39 +30,82 @@ public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer<Por
@Override @Override
protected void renderSafe(PortableStorageInterfaceTileEntity te, float partialTicks, MatrixStack ms, protected void renderSafe(PortableStorageInterfaceTileEntity te, float partialTicks, MatrixStack ms,
IRenderTypeBuffer buffer, int light, int overlay) { IRenderTypeBuffer buffer, int light, int overlay) {
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
SuperByteBuffer middle = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE.renderOn(blockState); float progress = te.getExtensionDistance(partialTicks);
SuperByteBuffer top = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_TOP.renderOn(blockState);
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
render(blockState, progress, te.isConnected(), sbb -> sbb.renderInto(ms, vb), ms);
}
public static void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal,
IRenderTypeBuffer buffer) {
BlockState blockState = context.state;
PortableStorageInterfaceTileEntity te = getTargetPSI(context);
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
float renderPartialTicks = Minecraft.getInstance()
.getRenderPartialTicks();
float progress = 0;
boolean lit = false;
if (te != null) {
progress = te.getExtensionDistance(renderPartialTicks);
lit = te.isConnected();
}
render(blockState, progress, lit, sbb -> sbb.light(msLocal.peek()
.getModel())
.renderInto(ms, vb), ms, msLocal);
}
protected static PortableStorageInterfaceTileEntity getTargetPSI(MovementContext context) {
String _workingPos_ = PortableStorageInterfaceMovement._workingPos_;
if (!context.contraption.stalled || !context.data.contains(_workingPos_))
return null;
BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_));
TileEntity tileEntity = context.world.getTileEntity(pos);
if (!(tileEntity instanceof PortableStorageInterfaceTileEntity))
return null;
PortableStorageInterfaceTileEntity psi = (PortableStorageInterfaceTileEntity) tileEntity;
if (!psi.isTransferring())
return null;
return psi;
}
private static void render(BlockState blockState, float progress, boolean lit,
Consumer<SuperByteBuffer> drawCallback, MatrixStack... matrixStacks) {
for (MatrixStack ms : matrixStacks)
ms.push(); ms.push();
SuperByteBuffer middle = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE.renderOn(blockState);
SuperByteBuffer top = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_TOP.renderOn(blockState);
if (lit)
middle = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED.renderOn(blockState);
Direction facing = blockState.get(PortableStorageInterfaceBlock.FACING); Direction facing = blockState.get(PortableStorageInterfaceBlock.FACING);
for (MatrixStack ms : matrixStacks)
MatrixStacker.of(ms) MatrixStacker.of(ms)
.centre() .centre()
.rotateY(AngleHelper.horizontalAngle(facing)) .rotateY(AngleHelper.horizontalAngle(facing))
.rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90)
.unCentre(); .unCentre();
float progress = (float) ((AnimationTickHolder.getRenderTick() * .25f) % (Math.PI * 2)); for (MatrixStack ms : matrixStacks) {
float bounce = (MathHelper.sin(progress) + 1) / 4f; ms.translate(0, progress / 2f, 0);
ms.push();
if (bounce > 7/16f) { ms.translate(0, 6 / 16f, 0);
middle = AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED.renderOn(blockState);
} }
drawCallback.accept(middle);
ms.translate(0, bounce, 0); for (MatrixStack ms : matrixStacks) {
ms.push();
ms.translate(0, 6/16f, 0);
middle.renderInto(ms, vb);
ms.pop(); ms.pop();
ms.translate(0, progress / 2f, 0);
}
ms.translate(0, bounce, 0); drawCallback.accept(top);
top.renderInto(ms, vb);
for (MatrixStack ms : matrixStacks)
ms.pop(); ms.pop();
} }

View file

@ -3,54 +3,150 @@ package com.simibubi.create.content.contraptions.components.actors;
import java.util.List; import java.util.List;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHandlerWrapper;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.SyncedTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.LerpedFloat;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class PortableStorageInterfaceTileEntity extends SmartTileEntity { public class PortableStorageInterfaceTileEntity extends SmartTileEntity {
protected int transferTimeout; protected int transferTimer;
protected float distance;
protected LazyOptional<IItemHandlerModifiable> capability; protected LazyOptional<IItemHandlerModifiable> capability;
protected LerpedFloat connectionAnimation;
public PortableStorageInterfaceTileEntity(TileEntityType<?> tileEntityTypeIn) { public PortableStorageInterfaceTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn); super(tileEntityTypeIn);
transferTimeout = 0; transferTimer = 0;
capability = LazyOptional.empty(); capability = LazyOptional.empty();
connectionAnimation = LerpedFloat.linear().startWithValue(0);
} }
public void startTransferringTo(Contraption contraption) { public void startTransferringTo(Contraption contraption, float distance) {
CombinedInvWrapper inventory = contraption.inventory;
capability.invalidate(); capability.invalidate();
capability = LazyOptional.of(() -> inventory); capability = LazyOptional.of(() -> new InterfaceItemHandler(contraption.inventory));
this.distance = distance;
startConnecting();
notifyUpdate();
} }
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
boolean wasConnected = isConnected();
if (transferTimer > 0) {
transferTimer--;
if (transferTimer == 0)
capability.invalidate();
}
boolean isConnected = isConnected();
if (wasConnected != isConnected && !world.isRemote)
markDirty();
float progress = 0;
int timeUnit = getTransferTimeout() / 2;
if (isConnected)
progress = 1;
else if (transferTimer >= timeUnit * 3)
progress = MathHelper.lerp((transferTimer - timeUnit * 3) / (float) timeUnit, 1, 0);
else if (transferTimer < timeUnit)
progress = MathHelper.lerp(transferTimer / (float) timeUnit, 0, 1);
connectionAnimation.setValue(progress);
}
@Override
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
transferTimer = compound.getInt("Timer");
distance = compound.getFloat("Distance");
}
@Override
protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound, clientPacket);
compound.putInt("Timer", transferTimer);
compound.putFloat("Distance", distance);
} }
public boolean isTransferring() { public boolean isTransferring() {
return transferTimeout != 0; return transferTimer != 0;
}
boolean isConnected() {
int timeUnit = getTransferTimeout() / 2;
return transferTimer >= timeUnit && transferTimer < timeUnit * 3;
}
float getExtensionDistance(float partialTicks) {
return connectionAnimation.getValue(partialTicks) * distance / 2;
}
float getConnectionDistance() {
return distance;
} }
@Override @Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) { public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (isItemHandlerCap(cap))
return capability.cast();
return super.getCapability(cap, side); return super.getCapability(cap, side);
} }
public void resetTimer() { public void startConnecting() {
transferTimer = getTransferTimeout() * 2;
}
public void onContentTransferred() {
int timeUnit = getTransferTimeout() / 2;
transferTimer = timeUnit * 3;
sendData();
}
protected Integer getTransferTimeout() {
return AllConfigs.SERVER.logistics.psiTimeout.get();
} }
@Override @Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {} public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
class InterfaceItemHandler extends ItemHandlerWrapper {
public InterfaceItemHandler(IItemHandlerModifiable wrapped) {
super(wrapped);
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
if (!isConnected())
return ItemStack.EMPTY;
ItemStack extractItem = super.extractItem(slot, amount, simulate);
if (!simulate && !extractItem.isEmpty())
onContentTransferred();
return extractItem;
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (!isConnected())
return stack;
ItemStack insertItem = super.insertItem(slot, stack, simulate);
if (!simulate && !insertItem.equals(stack, false))
onContentTransferred();
return insertItem;
}
}
} }

View file

@ -0,0 +1,49 @@
package com.simibubi.create.foundation.item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandlerModifiable;
public class ItemHandlerWrapper implements IItemHandlerModifiable {
private IItemHandlerModifiable wrapped;
public ItemHandlerWrapper(IItemHandlerModifiable wrapped) {
this.wrapped = wrapped;
}
@Override
public int getSlots() {
return wrapped.getSlots();
}
@Override
public ItemStack getStackInSlot(int slot) {
return wrapped.getStackInSlot(slot);
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
return wrapped.insertItem(slot, stack, simulate);
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
return wrapped.extractItem(slot, amount, simulate);
}
@Override
public int getSlotLimit(int slot) {
return wrapped.getSlotLimit(slot);
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return wrapped.isItemValid(slot, stack);
}
@Override
public void setStackInSlot(int slot, ItemStack stack) {
wrapped.setStackInSlot(slot, stack);
}
}

View file

@ -11,6 +11,9 @@ import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity { public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity {
@ -146,4 +149,12 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
return null; return null;
} }
protected boolean isItemHandlerCap(Capability<?> cap) {
return cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
}
protected boolean isFluidHandlerCap(Capability<?> cap) {
return cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
} }

View file

@ -6,7 +6,6 @@ import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
import com.simibubi.create.foundation.fluid.SmartFluidTank; import com.simibubi.create.foundation.fluid.SmartFluidTank;
import com.simibubi.create.foundation.item.SmartInventory;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;

View file

@ -36,6 +36,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
protected LazyOptional<IItemHandler> targetCapability; protected LazyOptional<IItemHandler> targetCapability;
protected boolean simulateNext; protected boolean simulateNext;
protected boolean bypassSided; protected boolean bypassSided;
private boolean findNewNextTick;
private BehaviourType<InvManipulationBehaviour> behaviourType; private BehaviourType<InvManipulationBehaviour> behaviourType;
@ -55,7 +56,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
InterfaceProvider target) { InterfaceProvider target) {
super(te); super(te);
behaviourType = type; behaviourType = type;
setLazyTickRate(40); setLazyTickRate(5);
this.target = target; this.target = target;
this.targetCapability = LazyOptional.empty(); this.targetCapability = LazyOptional.empty();
simulateNext = false; simulateNext = false;
@ -137,11 +138,12 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); super.initialize();
findNewCapability(); findNewNextTick = true;
} }
protected void onHandlerInvalidated(LazyOptional<IItemHandler> handler) { protected void onHandlerInvalidated(LazyOptional<IItemHandler> handler) {
findNewCapability(); findNewNextTick = true;
targetCapability = LazyOptional.empty();
} }
@Override @Override
@ -151,6 +153,15 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
findNewCapability(); findNewCapability();
} }
@Override
public void tick() {
super.tick();
if (findNewNextTick) {
findNewNextTick = false;
findNewCapability();
}
}
public int getAmountFromFilter() { public int getAmountFromFilter() {
int amount = -1; int amount = -1;
FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE); FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE);