From f291dbc03af2ea77bb42117c301367c7daad6792 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 17 May 2022 23:23:29 +0200 Subject: [PATCH] Global Storage - Carriages now track stored items and fluids - Fixed a number of inconsistencies in the new PSI behaviour - Fixed several issues with portal cut-off - PSIs can no longer interface with carriage contraptions that are located in two dimensions --- .../PortableFluidInterfaceTileEntity.java | 4 +- .../PortableItemInterfaceTileEntity.java | 6 +- .../PortableStorageInterfaceMovement.java | 35 ++-- .../PortableStorageInterfaceTileEntity.java | 21 ++ .../actors/SawMovementBehaviour.java | 20 +- .../dispenser/DropperMovementBehaviour.java | 24 ++- .../MovedDefaultDispenseItemBehaviour.java | 30 ++- .../deployer/DeployerMovementBehaviour.java | 4 +- .../AbstractContraptionEntity.java | 23 ++- .../structureMovement/Contraption.java | 176 +++-------------- .../MountedStorageManager.java | 180 ++++++++++++++++++ .../structureMovement/MovementBehaviour.java | 26 +-- .../OrientedContraptionEntity.java | 18 +- .../mounted/MountedContraption.java | 18 +- .../sync/ContraptionFluidPacket.java | 6 +- .../block/funnel/FunnelMovementBehaviour.java | 29 ++- .../logistics/trains/TrackNodeLocation.java | 6 +- .../logistics/trains/entity/Carriage.java | 54 +++--- .../trains/entity/CarriageContraption.java | 34 +++- .../entity/CarriageContraptionEntity.java | 11 +- .../logistics/trains/entity/Train.java | 2 + 21 files changed, 450 insertions(+), 277 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java index 7caa7cdc8..ec1b2ff60 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java @@ -24,7 +24,7 @@ public class PortableFluidInterfaceTileEntity extends PortableStorageInterfaceTi @Override public void startTransferringTo(Contraption contraption, float distance) { LazyOptional oldcap = capability; - capability = LazyOptional.of(() -> new InterfaceFluidHandler(contraption.fluidInventory)); + capability = LazyOptional.of(() -> new InterfaceFluidHandler(contraption.getSharedFluidTanks())); oldcap.invalidate(); super.startTransferringTo(contraption, distance); } @@ -110,7 +110,7 @@ public class PortableFluidInterfaceTileEntity extends PortableStorageInterfaceTi keepAlive(); return drain; } - + public void keepAlive() { onContentTransferred(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java index 7007680ef..d729c6180 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java @@ -16,7 +16,7 @@ import net.minecraftforge.items.ItemStackHandler; public class PortableItemInterfaceTileEntity extends PortableStorageInterfaceTileEntity { protected LazyOptional capability; - + public PortableItemInterfaceTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); capability = createEmptyHandler(); @@ -25,7 +25,7 @@ public class PortableItemInterfaceTileEntity extends PortableStorageInterfaceTil @Override public void startTransferringTo(Contraption contraption, float distance) { LazyOptional oldCap = capability; - capability = LazyOptional.of(() -> new InterfaceItemHandler(contraption.inventory)); + capability = LazyOptional.of(() -> new InterfaceItemHandler(contraption.getSharedInventory())); oldCap.invalidate(); super.startTransferringTo(contraption, distance); } @@ -37,7 +37,7 @@ public class PortableItemInterfaceTileEntity extends PortableStorageInterfaceTil oldCap.invalidate(); super.stopTransferring(); } - + private LazyOptional createEmptyHandler() { return LazyOptional.of(() -> new InterfaceItemHandler(new ItemStackHandler(0))); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java index 18b21f18c..ca38086a5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java @@ -61,24 +61,26 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { @Override public void visitNewPosition(MovementContext context, BlockPos pos) { + boolean onCarriage = context.contraption instanceof CarriageContraption; + if (onCarriage && context.motion.length() > 1 / 4f) + return; if (!findInterface(context, pos)) context.data.remove(_workingPos_); -// if (findInterface(context, pos)) -// context.stall = true; } @Override public void tick(MovementContext context) { - if (context.world.isClientSide) { + if (context.world.isClientSide) getAnimation(context).tickChaser(); + + boolean onCarriage = context.contraption instanceof CarriageContraption; + if (onCarriage && context.motion.length() > 1 / 4f) + return; + + if (context.world.isClientSide) { BlockPos pos = new BlockPos(context.position); - findInterface(context, pos); - if (!context.data.contains(_clientPrevPos_) - || !NbtUtils.readBlockPos(context.data.getCompound(_clientPrevPos_)) - .equals(pos)) { - if (!findInterface(context, pos)) - reset(context); - } + if (!findInterface(context, pos)) + reset(context); return; } @@ -88,7 +90,7 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { BlockPos pos = NbtUtils.readBlockPos(context.data.getCompound(_workingPos_)); Vec3 target = VecHelper.getCenterOf(pos); - if (!context.stall + if (!context.stall && !onCarriage && context.position.closerThan(target, target.distanceTo(context.position.add(context.motion)))) context.stall = true; @@ -114,6 +116,8 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { } protected boolean findInterface(MovementContext context, BlockPos pos) { + if (context.contraption instanceof CarriageContraption cc && !cc.notInPortal()) + return false; Optional currentFacingIfValid = getCurrentFacingIfValid(context); if (!currentFacingIfValid.isPresent()) return false; @@ -121,9 +125,10 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { Direction currentFacing = currentFacingIfValid.get(); PortableStorageInterfaceTileEntity psi = findStationaryInterface(context.world, pos, context.state, currentFacing); + if (psi == null) return false; - if ((psi.isTransferring() || psi.isPowered()) && !context.world.isClientSide) + if (psi.isPowered()) return false; context.data.put(_workingPos_, NbtUtils.writeBlockPos(psi.getBlockPos())); @@ -170,14 +175,16 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { private PortableStorageInterfaceTileEntity getStationaryInterfaceAt(Level world, BlockPos pos, BlockState state, Direction facing) { BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof PortableStorageInterfaceTileEntity)) + if (!(te instanceof PortableStorageInterfaceTileEntity psi)) return null; BlockState blockState = world.getBlockState(pos); if (blockState.getBlock() != state.getBlock()) return null; if (blockState.getValue(PortableStorageInterfaceBlock.FACING) != facing.getOpposite()) return null; - return (PortableStorageInterfaceTileEntity) te; + if (psi.isPowered()) + return null; + return psi; } private Optional getCurrentFacingIfValid(MovementContext context) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java index 1a96819f1..c710e34c3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.actors; import java.util.List; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; @@ -52,6 +53,14 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity return connectedEntity != null && isConnected(); } + @Override + public void initialize() { + super.initialize(); + powered = level.hasNeighborSignal(worldPosition); + if (!powered) + notifyContraptions(); + } + protected abstract void invalidateCapability(); @Override @@ -109,7 +118,10 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity super.read(compound, clientPacket); transferTimer = compound.getInt("Timer"); distance = compound.getFloat("Distance"); + boolean poweredPreviously = powered; powered = compound.getBoolean("Powered"); + if (clientPacket && powered != poweredPreviously && !powered) + notifyContraptions(); } @Override @@ -125,9 +137,18 @@ public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity if (isBlockPowered == powered) return; powered = isBlockPowered; + if (!powered) + notifyContraptions(); + if (powered) + stopTransferring(); sendData(); } + private void notifyContraptions() { + level.getEntitiesOfClass(AbstractContraptionEntity.class, new AABB(worldPosition).inflate(3)) + .forEach(AbstractContraptionEntity::refreshPSIs); + } + public boolean isPowered() { return powered; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java index 3f429b54c..17965f864 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java @@ -36,17 +36,21 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public Vec3 getActiveAreaOffset(MovementContext context) { - return Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING).getNormal()).scale(.65f); + return Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING) + .getNormal()) + .scale(.65f); } @Override public void visitNewPosition(MovementContext context, BlockPos pos) { super.visitNewPosition(context, pos); - Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING).getNormal()); + Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING) + .getNormal()); facingVec = context.rotation.apply(facingVec); Direction closestToFacing = Direction.getNearest(facingVec.x, facingVec.y, facingVec.z); - if(closestToFacing.getAxis().isVertical() && context.data.contains("BreakingPos")) { + if (closestToFacing.getAxis() + .isVertical() && context.data.contains("BreakingPos")) { context.data.remove("BreakingPos"); context.stall = false; } @@ -64,15 +68,17 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { Optional dynamicTree = TreeCutter.findDynamicTree(brokenState.getBlock(), pos); if (dynamicTree.isPresent()) { - dynamicTree.get().destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); + dynamicTree.get() + .destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); return; } - TreeCutter.findTree(context.world, pos).destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); + TreeCutter.findTree(context.world, pos) + .destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); } public void dropItemFromCutTree(MovementContext context, BlockPos pos, ItemStack stack) { - ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, stack, false); + ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.getSharedInventory(), stack, false); if (remainder.isEmpty()) return; @@ -87,7 +93,7 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override @OnlyIn(value = Dist.CLIENT) public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { + ContraptionMatrices matrices, MultiBufferSource buffer) { SawRenderer.renderInContraption(context, renderWorld, matrices, buffer); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java index 9e28bce93..03bf61698 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java @@ -15,7 +15,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; public class DropperMovementBehaviour implements MovementBehaviour { - protected static final MovedDefaultDispenseItemBehaviour DEFAULT_BEHAVIOUR = new MovedDefaultDispenseItemBehaviour(); + protected static final MovedDefaultDispenseItemBehaviour DEFAULT_BEHAVIOUR = + new MovedDefaultDispenseItemBehaviour(); private static final Random RNG = new Random(); protected void activate(MovementContext context, BlockPos pos) { @@ -23,7 +24,8 @@ public class DropperMovementBehaviour implements MovementBehaviour { if (location.isEmpty()) { context.world.levelEvent(1001, pos, 0); } else { - setItemStackAt(location, DEFAULT_BEHAVIOUR.dispense(getItemStackAt(location, context), context, pos), context); + setItemStackAt(location, DEFAULT_BEHAVIOUR.dispense(getItemStackAt(location, context), context, pos), + context); } } @@ -36,8 +38,13 @@ public class DropperMovementBehaviour implements MovementBehaviour { } private void collectItems(MovementContext context) { - getStacks(context).stream().filter(itemStack -> !itemStack.isEmpty() && itemStack.getItem() != Items.AIR && itemStack.getMaxStackSize() > itemStack.getCount()).forEach(itemStack -> itemStack.grow( - ItemHelper.extract(context.contraption.inventory, itemStack::sameItem, ItemHelper.ExtractionCountMode.UPTO, itemStack.getMaxStackSize() - itemStack.getCount(), false).getCount())); + getStacks(context).stream() + .filter(itemStack -> !itemStack.isEmpty() && itemStack.getItem() != Items.AIR + && itemStack.getMaxStackSize() > itemStack.getCount()) + .forEach(itemStack -> itemStack.grow(ItemHelper + .extract(context.contraption.getSharedInventory(), itemStack::sameItem, + ItemHelper.ExtractionCountMode.UPTO, itemStack.getMaxStackSize() - itemStack.getCount(), false) + .getCount())); } private void updateTemporaryData(MovementContext context) { @@ -62,7 +69,8 @@ public class DropperMovementBehaviour implements MovementBehaviour { if (testStack == null || testStack.isEmpty()) continue; if (testStack.getMaxStackSize() == 1) { - location = new DispenseItemLocation(false, ItemHelper.findFirstMatchingSlotIndex(context.contraption.inventory, testStack::sameItem)); + location = new DispenseItemLocation(false, ItemHelper + .findFirstMatchingSlotIndex(context.contraption.getSharedInventory(), testStack::sameItem)); if (!getItemStackAt(location, context).isEmpty()) useable.add(location); } else if (testStack.getCount() >= 2) @@ -104,7 +112,8 @@ public class DropperMovementBehaviour implements MovementBehaviour { if (location.isInternal()) { return getStacks(context).get(location.getSlot()); } else { - return context.contraption.inventory.getStackInSlot(location.getSlot()); + return context.contraption.getSharedInventory() + .getStackInSlot(location.getSlot()); } } @@ -112,7 +121,8 @@ public class DropperMovementBehaviour implements MovementBehaviour { if (location.isInternal()) { getStacks(context).set(location.getSlot(), stack); } else { - context.contraption.inventory.setStackInSlot(location.getSlot(), stack); + context.contraption.getSharedInventory() + .setStackInSlot(location.getSlot(), stack); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java index d81a88c44..45b5a89d7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java @@ -17,11 +17,13 @@ import net.minecraftforge.items.ItemHandlerHelper; public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBehaviour { private static final MovedDefaultDispenseItemBehaviour DEFAULT_INSTANCE = new MovedDefaultDispenseItemBehaviour(); - public static void doDispense(Level p_82486_0_, ItemStack p_82486_1_, int p_82486_2_, Vec3 facing, BlockPos p_82486_4_, MovementContext context) { + public static void doDispense(Level p_82486_0_, ItemStack p_82486_1_, int p_82486_2_, Vec3 facing, + BlockPos p_82486_4_, MovementContext context) { double d0 = p_82486_4_.getX() + facing.x + .5; double d1 = p_82486_4_.getY() + facing.y + .5; double d2 = p_82486_4_.getZ() + facing.z + .5; - if (Direction.getNearest(facing.x, facing.y, facing.z).getAxis() == Direction.Axis.Y) { + if (Direction.getNearest(facing.x, facing.y, facing.z) + .getAxis() == Direction.Axis.Y) { d1 = d1 - 0.125D; } else { d1 = d1 - 0.15625D; @@ -29,13 +31,20 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha ItemEntity itementity = new ItemEntity(p_82486_0_, d0, d1, d2, p_82486_1_); double d3 = p_82486_0_.random.nextDouble() * 0.1D + 0.2D; - itementity.setDeltaMovement(p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.x() * d3 + context.motion.x, p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.y() * d3 + context.motion.y, p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.z() * d3 + context.motion.z); + itementity.setDeltaMovement( + p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.x() * d3 + + context.motion.x, + p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.y() * d3 + + context.motion.y, + p_82486_0_.random.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.z() * d3 + + context.motion.z); p_82486_0_.addFreshEntity(itementity); } @Override public ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos) { - Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(DispenserBlock.FACING).getNormal()); + Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(DispenserBlock.FACING) + .getNormal()); facingVec = context.rotation.apply(facingVec); facingVec.normalize(); @@ -46,7 +55,9 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha this.spawnDispenseParticles(context.world, pos, closestToFacing); return this.dispenseStack(itemStack, context, pos, facingVec); } else { - if (HopperBlockEntity.addItem(null, iinventory, itemStack.copy().split(1), closestToFacing.getOpposite()).isEmpty()) + if (HopperBlockEntity.addItem(null, iinventory, itemStack.copy() + .split(1), closestToFacing.getOpposite()) + .isEmpty()) itemStack.shrink(1); return itemStack; } @@ -69,7 +80,8 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha } /** - * Order clients to display dispense particles from the specified block and facing. + * Order clients to display dispense particles from the specified block and + * facing. */ protected void spawnDispenseParticles(LevelAccessor world, BlockPos pos, Vec3 facing) { spawnDispenseParticles(world, pos, getClosestFacingDirection(facing)); @@ -83,9 +95,11 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha return Direction.getNearest(exactFacing.x, exactFacing.y, exactFacing.z); } - protected ItemStack placeItemInInventory(ItemStack consumedFrom, ItemStack output, MovementContext context, BlockPos pos, Vec3 facing) { + protected ItemStack placeItemInInventory(ItemStack consumedFrom, ItemStack output, MovementContext context, + BlockPos pos, Vec3 facing) { consumedFrom.shrink(1); - ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, output.copy(), false); + ItemStack remainder = + ItemHandlerHelper.insertItem(context.contraption.getSharedInventory(), output.copy(), false); if (!remainder.isEmpty()) DEFAULT_INSTANCE.dispenseStack(output, context, pos, facing); return consumedFrom; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java index 720bc8ae0..2c79b9a28 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java @@ -123,7 +123,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour { ItemStack firstRequired = requiredItems.isEmpty() ? ItemStack.EMPTY : requiredItems.get(0).item; if (!context.contraption.hasUniversalCreativeCrate) { - IItemHandler iItemHandler = context.contraption.inventory; + IItemHandler iItemHandler = context.contraption.getSharedInventory(); for (ItemRequirement.StackRequirement required : requiredItems) { int amountFound = ItemHelper .extract(iItemHandler, s -> ItemRequirement.validate(required.item, s), ExtractionCountMode.UPTO, @@ -202,7 +202,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour { ItemStack filter = getFilter(context); if (AllItems.SCHEMATIC.isIn(filter)) return; - ItemStack held = ItemHelper.extract(context.contraption.inventory, + ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), stack -> FilterItem.test(context.world, stack, filter), 1, false); player.setItemInHand(InteractionHand.MAIN_HAND, held); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index 45c07c655..0484af53e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -21,12 +21,14 @@ import com.simibubi.create.AllItems; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement; import com.simibubi.create.content.contraptions.components.actors.SeatBlock; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsStopControllingPacket; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.mixin.accessor.ServerLevelAccessor; import com.simibubi.create.foundation.networking.AllPackets; @@ -294,10 +296,11 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit if (!initialized) contraptionInitialize(); - contraption.onEntityTick(level); + + contraption.storage.entityTick(this); tickContraption(); super.tick(); - + if (!(level instanceof ServerLevelAccessor sl)) return; @@ -353,6 +356,9 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit StructureBlockInfo blockInfo = pair.left; MovementBehaviour actor = AllMovementBehaviours.of(blockInfo.state); + if (actor == null) + continue; + Vec3 oldMotion = context.motion; Vec3 actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos) .add(actor.getActiveAreaOffset(context)), 1); @@ -408,6 +414,16 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit contraption.stalled = isStalled(); } + public void refreshPSIs() { + for (MutablePair pair : contraption.getActors()) { + MovementContext context = pair.right; + StructureBlockInfo blockInfo = pair.left; + MovementBehaviour actor = AllMovementBehaviours.of(blockInfo.state); + if (actor instanceof PortableStorageInterfaceMovement && isActorActive(context, actor)) + actor.visitNewPosition(context, new BlockPos(context.position)); + } + } + protected boolean isActorActive(MovementContext context, MovementBehaviour actor) { return actor.isActive(context); } @@ -428,7 +444,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit relativeMotion = reverseRotation(relativeMotion, 1); context.relativeMotion = relativeMotion; return !new BlockPos(previousPosition).equals(gridPosition) - || context.relativeMotion.length() > 0 && context.firstMovement; + || (context.relativeMotion.length() > 0 || context.contraption instanceof CarriageContraption) + && context.firstMovement; } public void move(double x, double y, double z) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index d11a03226..b49ec4883 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -4,7 +4,6 @@ import static com.simibubi.create.content.contraptions.components.structureMovem import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -19,7 +18,6 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; -import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -63,7 +61,6 @@ import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.utility.BlockFace; @@ -85,7 +82,6 @@ import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.village.poi.PoiType; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; @@ -114,10 +110,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.fluids.capability.templates.FluidTank; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.registries.GameData; @@ -126,22 +119,20 @@ public abstract class Contraption { public Optional> simplifiedEntityColliders; public AbstractContraptionEntity entity; - public ContraptionInvWrapper inventory; - public CombinedTankWrapper fluidInventory; + public AABB bounds; public BlockPos anchor; public boolean stalled; public boolean hasUniversalCreativeCrate; protected Map blocks; - protected Map storage; - protected Map fluidStorage; protected List> actors; protected Map interactors; protected List superglue; protected List seats; protected Map seatMapping; protected Map stabilizedSubContraptions; + protected MountedStorageManager storage; private Set glueToRemove; private Map initialPassengers; @@ -158,13 +149,11 @@ public abstract class Contraption { public Contraption() { blocks = new HashMap<>(); - storage = new HashMap<>(); seats = new ArrayList<>(); actors = new ArrayList<>(); interactors = new HashMap<>(); superglue = new ArrayList<>(); seatMapping = new HashMap<>(); - fluidStorage = new HashMap<>(); glueToRemove = new HashSet<>(); initialPassengers = new HashMap<>(); presentTileEntities = new HashMap<>(); @@ -173,6 +162,7 @@ public abstract class Contraption { pendingSubContraptions = new ArrayList<>(); stabilizedSubContraptions = new HashMap<>(); simplifiedEntityColliders = Optional.empty(); + storage = new MountedStorageManager(); } public ContraptionWorld getContraptionWorld() { @@ -255,20 +245,7 @@ public abstract class Contraption { stabilizedSubContraptions.put(movedContraption.getUUID(), new BlockFace(toLocalPos(pos), face)); } - // Gather itemhandlers of mounted storage - List list = storage.values() - .stream() - .map(MountedStorage::getItemHandler) - .collect(Collectors.toList()); - inventory = - new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); - - List fluidHandlers = fluidStorage.values() - .stream() - .map(MountedFluidStorage::getFluidHandler) - .collect(Collectors.toList()); - fluidInventory = new CombinedTankWrapper( - Arrays.copyOf(fluidHandlers.toArray(), fluidHandlers.size(), IFluidHandler[].class)); + storage.createHandlers(); gatherBBsOffThread(); } @@ -300,10 +277,6 @@ public abstract class Contraption { } } - public void onEntityTick(Level world) { - fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, world.isClientSide)); - } - /** move the first block in frontier queue */ protected boolean moveBlock(Level world, @Nullable Direction forcedDirection, Queue frontier, Set visited) throws AssemblyException { @@ -642,10 +615,7 @@ public abstract class Contraption { bounds = bounds.minmax(new AABB(localPos)); BlockEntity te = pair.getValue(); - if (te != null && MountedStorage.canUseAsStorage(te)) - storage.put(localPos, new MountedStorage(te)); - if (te != null && MountedFluidStorage.canUseAsStorage(te)) - fluidStorage.put(localPos, new MountedFluidStorage(te)); + storage.addBlock(localPos, te); if (AllMovementBehaviours.contains(captured.state.getBlock())) actors.add(MutablePair.of(StructureBlockInfo, null)); if (AllInteractionBehaviours.contains(captured.state.getBlock())) @@ -722,14 +692,6 @@ public abstract class Contraption { NBTHelper.iterateCompoundList(nbt.getList("SubContraptions", Tag.TAG_COMPOUND), c -> stabilizedSubContraptions.put(c.getUUID("Id"), BlockFace.fromNBT(c.getCompound("Location")))); - storage.clear(); - NBTHelper.iterateCompoundList(nbt.getList("Storage", Tag.TAG_COMPOUND), c -> storage - .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedStorage.deserialize(c.getCompound("Data")))); - - fluidStorage.clear(); - NBTHelper.iterateCompoundList(nbt.getList("FluidStorage", Tag.TAG_COMPOUND), c -> fluidStorage - .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedFluidStorage.deserialize(c.getCompound("Data")))); - interactors.clear(); NBTHelper.iterateCompoundList(nbt.getList("Interactors", Tag.TAG_COMPOUND), c -> { BlockPos pos = NbtUtils.readBlockPos(c.getCompound("Pos")); @@ -738,32 +700,7 @@ public abstract class Contraption { interactors.put(pos, behaviour); }); - if (spawnData) - fluidStorage.forEach((pos, mfs) -> { - BlockEntity tileEntity = presentTileEntities.get(pos); - if (!(tileEntity instanceof FluidTankTileEntity)) - return; - FluidTankTileEntity tank = (FluidTankTileEntity) tileEntity; - IFluidTank tankInventory = tank.getTankInventory(); - if (tankInventory instanceof FluidTank) - ((FluidTank) tankInventory).setFluid(mfs.tank.getFluid()); - tank.getFluidLevel() - .startWithValue(tank.getFillState()); - mfs.assignTileEntity(tank); - }); - - IItemHandlerModifiable[] handlers = new IItemHandlerModifiable[storage.size()]; - int index = 0; - for (MountedStorage mountedStorage : storage.values()) - handlers[index++] = mountedStorage.getItemHandler(); - - IFluidHandler[] fluidHandlers = new IFluidHandler[fluidStorage.size()]; - index = 0; - for (MountedFluidStorage mountedStorage : fluidStorage.values()) - fluidHandlers[index++] = mountedStorage.getFluidHandler(); - - inventory = new ContraptionInvWrapper(handlers); - fluidInventory = new CombinedTankWrapper(fluidHandlers); + storage.read(nbt, presentTileEntities, spawnData); if (nbt.contains("BoundsFront")) bounds = NBTHelper.readAABB(nbt.getList("BoundsFront", 5)); @@ -790,35 +727,15 @@ public abstract class Contraption { } ListTag superglueNBT = new ListTag(); - ListTag storageNBT = new ListTag(); if (!spawnPacket) { for (AABB glueEntry : superglue) { CompoundTag c = new CompoundTag(); SuperGlueEntity.writeBoundingBox(c, glueEntry); superglueNBT.add(c); } - - for (BlockPos pos : storage.keySet()) { - CompoundTag c = new CompoundTag(); - MountedStorage mountedStorage = storage.get(pos); - if (!mountedStorage.isValid()) - continue; - c.put("Pos", NbtUtils.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - storageNBT.add(c); - } } - ListTag fluidStorageNBT = new ListTag(); - for (BlockPos pos : fluidStorage.keySet()) { - CompoundTag c = new CompoundTag(); - MountedFluidStorage mountedStorage = fluidStorage.get(pos); - if (!mountedStorage.isValid()) - continue; - c.put("Pos", NbtUtils.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - fluidStorageNBT.add(c); - } + storage.write(nbt, spawnPacket); ListTag interactorNBT = new ListTag(); for (BlockPos pos : interactors.keySet()) { @@ -847,8 +764,6 @@ public abstract class Contraption { nbt.put("Actors", actorsNBT); nbt.put("Interactors", interactorNBT); nbt.put("Superglue", superglueNBT); - nbt.put("Storage", storageNBT); - nbt.put("FluidStorage", fluidStorageNBT); nbt.put("Anchor", NbtUtils.writeBlockPos(anchor)); nbt.putBoolean("Stalled", stalled); nbt.putBoolean("BottomlessSupply", hasUniversalCreativeCrate); @@ -962,10 +877,7 @@ public abstract class Contraption { } public void removeBlocksFromWorld(Level world, BlockPos offset) { - storage.values() - .forEach(MountedStorage::removeStorageFromWorld); - fluidStorage.values() - .forEach(MountedFluidStorage::removeStorageFromWorld); + storage.removeStorageFromWorld(); glueToRemove.forEach(glue -> { superglue.add(glue.getBoundingBox() @@ -1125,23 +1037,13 @@ public abstract class Contraption { tag.put("LastKnownPos", NbtUtils.writeBlockPos(BlockPos.ZERO.below(Integer.MAX_VALUE - 1))); tileEntity.load(tag); - - if (storage.containsKey(block.pos)) { - MountedStorage mountedStorage = storage.get(block.pos); - if (mountedStorage.isValid()) - mountedStorage.addStorageToWorld(tileEntity); - } - - if (fluidStorage.containsKey(block.pos)) { - MountedFluidStorage mountedStorage = fluidStorage.get(block.pos); - if (mountedStorage.isValid()) - mountedStorage.addStorageToWorld(tileEntity); - } + storage.addStorageToWorld(block, tileEntity); } transform.apply(tileEntity); } } + for (StructureBlockInfo block : blocks.values()) { if (!shouldUpdateAfterMovement(block)) continue; @@ -1149,20 +1051,15 @@ public abstract class Contraption { world.markAndNotifyBlock(targetPos, world.getChunkAt(targetPos), block.state, block.state, Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_ALL, 512); } - - for (int i = 0; i < inventory.getSlots(); i++) { - if (!inventory.isSlotExternal(i)) - inventory.setStackInSlot(i, ItemStack.EMPTY); - } - for (int i = 0; i < fluidInventory.getTanks(); i++) - fluidInventory.drain(fluidInventory.getFluidInTank(i), FluidAction.EXECUTE); - + for (AABB box : superglue) { box = new AABB(transform.apply(new Vec3(box.minX, box.minY, box.minZ)), transform.apply(new Vec3(box.maxX, box.maxY, box.maxZ))); if (!world.isClientSide) world.addFreshEntity(new SuperGlueEntity(world, box)); } + + storage.clear(); } public void addPassengersToWorld(Level world, StructureTransform transform, List seatedEntities) { @@ -1240,8 +1137,6 @@ public abstract class Contraption { bounds = new AABB(minX, minY, minZ, maxX, maxY, maxZ); } - public void addExtraInventories(Entity entity) {} - public Map getSeatMapping() { return seatMapping; } @@ -1282,12 +1177,6 @@ public abstract class Contraption { return interactors; } - public void updateContainedFluid(BlockPos localPos, FluidStack containedFluid) { - MountedFluidStorage mountedFluidStorage = fluidStorage.get(localPos); - if (mountedFluidStorage != null) - mountedFluidStorage.updateFluid(containedFluid); - } - @OnlyIn(Dist.CLIENT) public ContraptionLighter makeLighter() { // TODO: move lighters to registry @@ -1349,39 +1238,22 @@ public abstract class Contraption { return maxDistSq; } - // TODO: unused? -// private static class ContraptionTileWorld extends WrappedWorld implements IFlywheelWorld { -// -// private final BlockEntity te; -// private final StructureBlockInfo info; -// -// public ContraptionTileWorld(Level world, BlockEntity te, StructureBlockInfo info) { -// super(world); -// this.te = te; -// this.info = info; -// } -// -// @Override -// public BlockState getBlockState(BlockPos pos) { -// if (!pos.equals(te.getBlockPos())) -// return Blocks.AIR.defaultBlockState(); -// return info.state; -// } -// -// @Override -// public boolean isLoaded(BlockPos pos) { -// return pos.equals(te.getBlockPos()); -// } -// } + public IItemHandlerModifiable getSharedInventory() { + return storage.getItems(); + } + + public IFluidHandler getSharedFluidTanks() { + return storage.getFluids(); + } public Collection getRenderedBlocks() { return blocks.values(); } - + public Collection getSpecialRenderedTEs() { return specialRenderedTileEntities; } - + public boolean isHiddenInPortal(BlockPos localPos) { return false; } @@ -1389,6 +1261,10 @@ public abstract class Contraption { public Optional> getSimplifiedEntityColliders() { return simplifiedEntityColliders; } + + public void handleContraptionFluidPacket(BlockPos localPos, FluidStack containedFluid) { + storage.updateContainedFluid(localPos, containedFluid); + } public static class ContraptionInvWrapper extends CombinedInvWrapper { protected final boolean isExternal; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java new file mode 100644 index 000000000..c7af7ba38 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java @@ -0,0 +1,180 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption.ContraptionInvWrapper; +import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; +import com.simibubi.create.foundation.fluid.CombinedTankWrapper; +import com.simibubi.create.foundation.utility.NBTHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class MountedStorageManager { + + private ContraptionInvWrapper inventory; + private CombinedTankWrapper fluidInventory; + private Map storage; + private Map fluidStorage; + + public MountedStorageManager() { + storage = new HashMap<>(); + fluidStorage = new HashMap<>(); + } + + public void entityTick(AbstractContraptionEntity entity) { + fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, entity.level.isClientSide)); + } + + public void createHandlers() { + List list = storage.values() + .stream() + .map(MountedStorage::getItemHandler) + .collect(Collectors.toList()); + inventory = + new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); + + List fluidHandlers = fluidStorage.values() + .stream() + .map(MountedFluidStorage::getFluidHandler) + .collect(Collectors.toList()); + fluidInventory = new CombinedTankWrapper( + Arrays.copyOf(fluidHandlers.toArray(), fluidHandlers.size(), IFluidHandler[].class)); + } + + public void addBlock(BlockPos localPos, BlockEntity te) { + if (te != null && MountedStorage.canUseAsStorage(te)) + storage.put(localPos, new MountedStorage(te)); + if (te != null && MountedFluidStorage.canUseAsStorage(te)) + fluidStorage.put(localPos, new MountedFluidStorage(te)); + } + + public void read(CompoundTag nbt, Map presentTileEntities, boolean clientPacket) { + storage.clear(); + NBTHelper.iterateCompoundList(nbt.getList("Storage", Tag.TAG_COMPOUND), c -> storage + .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedStorage.deserialize(c.getCompound("Data")))); + + fluidStorage.clear(); + NBTHelper.iterateCompoundList(nbt.getList("FluidStorage", Tag.TAG_COMPOUND), c -> fluidStorage + .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedFluidStorage.deserialize(c.getCompound("Data")))); + + if (clientPacket && presentTileEntities != null) + fluidStorage.forEach((pos, mfs) -> { + BlockEntity tileEntity = presentTileEntities.get(pos); + if (!(tileEntity instanceof FluidTankTileEntity)) + return; + FluidTankTileEntity tank = (FluidTankTileEntity) tileEntity; + IFluidTank tankInventory = tank.getTankInventory(); + if (tankInventory instanceof FluidTank) + ((FluidTank) tankInventory).setFluid(mfs.tank.getFluid()); + tank.getFluidLevel() + .startWithValue(tank.getFillState()); + mfs.assignTileEntity(tank); + }); + + IItemHandlerModifiable[] handlers = new IItemHandlerModifiable[storage.size()]; + int index = 0; + for (MountedStorage mountedStorage : storage.values()) + handlers[index++] = mountedStorage.getItemHandler(); + + IFluidHandler[] fluidHandlers = new IFluidHandler[fluidStorage.size()]; + index = 0; + for (MountedFluidStorage mountedStorage : fluidStorage.values()) + fluidHandlers[index++] = mountedStorage.getFluidHandler(); + + inventory = new ContraptionInvWrapper(handlers); + fluidInventory = new CombinedTankWrapper(fluidHandlers); + } + + public void write(CompoundTag nbt, boolean clientPacket) { + ListTag storageNBT = new ListTag(); + if (!clientPacket) + for (BlockPos pos : storage.keySet()) { + CompoundTag c = new CompoundTag(); + MountedStorage mountedStorage = storage.get(pos); + if (!mountedStorage.isValid()) + continue; + c.put("Pos", NbtUtils.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + storageNBT.add(c); + } + + ListTag fluidStorageNBT = new ListTag(); + for (BlockPos pos : fluidStorage.keySet()) { + CompoundTag c = new CompoundTag(); + MountedFluidStorage mountedStorage = fluidStorage.get(pos); + if (!mountedStorage.isValid()) + continue; + c.put("Pos", NbtUtils.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + fluidStorageNBT.add(c); + } + + nbt.put("Storage", storageNBT); + nbt.put("FluidStorage", fluidStorageNBT); + } + + public void removeStorageFromWorld() { + storage.values() + .forEach(MountedStorage::removeStorageFromWorld); + fluidStorage.values() + .forEach(MountedFluidStorage::removeStorageFromWorld); + } + + public void addStorageToWorld(StructureBlockInfo block, BlockEntity tileEntity) { + if (storage.containsKey(block.pos)) { + MountedStorage mountedStorage = storage.get(block.pos); + if (mountedStorage.isValid()) + mountedStorage.addStorageToWorld(tileEntity); + } + + if (fluidStorage.containsKey(block.pos)) { + MountedFluidStorage mountedStorage = fluidStorage.get(block.pos); + if (mountedStorage.isValid()) + mountedStorage.addStorageToWorld(tileEntity); + } + } + + public void clear() { + for (int i = 0; i < inventory.getSlots(); i++) + if (!inventory.isSlotExternal(i)) + inventory.setStackInSlot(i, ItemStack.EMPTY); + for (int i = 0; i < fluidInventory.getTanks(); i++) + fluidInventory.drain(fluidInventory.getFluidInTank(i), FluidAction.EXECUTE); + } + + public void updateContainedFluid(BlockPos localPos, FluidStack containedFluid) { + MountedFluidStorage mountedFluidStorage = fluidStorage.get(localPos); + if (mountedFluidStorage != null) + mountedFluidStorage.updateFluid(containedFluid); + } + + public void attachExternal(IItemHandlerModifiable externalStorage) { + inventory = new ContraptionInvWrapper(externalStorage, inventory); + } + + public IItemHandlerModifiable getItems() { + return inventory; + } + + public IFluidHandler getFluids() { + return fluidInventory; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java index 1d2a3445e..d5e58219a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java @@ -23,14 +23,11 @@ public interface MovementBehaviour { return true; } - default void tick(MovementContext context) { - } + default void tick(MovementContext context) {} - default void startMoving(MovementContext context) { - } + default void startMoving(MovementContext context) {} - default void visitNewPosition(MovementContext context, BlockPos pos) { - } + default void visitNewPosition(MovementContext context, BlockPos pos) {} default Vec3 getActiveAreaOffset(MovementContext context) { return Vec3.ZERO; @@ -39,7 +36,7 @@ public interface MovementBehaviour { default void dropItem(MovementContext context, ItemStack stack) { ItemStack remainder; if (AllConfigs.SERVER.kinetics.moveItemsToStorage.get()) - remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, stack, false); + remainder = ItemHandlerHelper.insertItem(context.contraption.getSharedInventory(), stack, false); else remainder = stack; if (remainder.isEmpty()) @@ -52,14 +49,11 @@ public interface MovementBehaviour { context.world.addFreshEntity(itemEntity); } - default void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) { - } + default void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) {} - default void stopMoving(MovementContext context) { - } + default void stopMoving(MovementContext context) {} - default void writeExtraData(MovementContext context) { - } + default void writeExtraData(MovementContext context) {} default boolean renderAsNormalTileEntity() { return false; @@ -71,12 +65,12 @@ public interface MovementBehaviour { @OnlyIn(Dist.CLIENT) default void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - } + ContraptionMatrices matrices, MultiBufferSource buffer) {} @OnlyIn(Dist.CLIENT) @Nullable - default ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, MovementContext context) { + default ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, + MovementContext context) { return null; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java index e8eac8883..286a6754e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java @@ -428,7 +428,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { .normalize() .scale(1)); if (fuel < 5 && contraption != null) { - ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false); + ItemStack coal = ItemHelper.extract(contraption.getSharedInventory(), FUEL_ITEMS, 1, false); if (!coal.isEmpty()) fuel += 3600; } @@ -457,15 +457,17 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { } protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) { - if (isOnCoupling) { - Couple coupledCarts = getCoupledCartsIfPresent(); - if (coupledCarts == null) - return; - coupledCarts.map(MinecartController::cart) - .forEach(contraption::addExtraInventories); + if (!(contraption instanceof MountedContraption mc)) + return; + if (!isOnCoupling) { + mc.addExtraInventories(riding); return; } - contraption.addExtraInventories(riding); + Couple coupledCarts = getCoupledCartsIfPresent(); + if (coupledCarts == null) + return; + coupledCarts.map(MinecartController::cart) + .forEach(mc::addExtraInventories); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java index fec9129c5..90f30b4ec 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java @@ -34,7 +34,6 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraft.world.phys.AABB; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; public class MountedContraption extends Contraption { @@ -95,8 +94,8 @@ public class MountedContraption extends Contraption { for (Axis axis : Iterate.axes) { if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis)) continue; - for (AbstractMinecart abstractMinecartEntity : world - .getEntitiesOfClass(AbstractMinecart.class, new AABB(pos))) { + for (AbstractMinecart abstractMinecartEntity : world.getEntitiesOfClass(AbstractMinecart.class, + new AABB(pos))) { if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity)) break; connectedCart = abstractMinecartEntity; @@ -118,8 +117,8 @@ public class MountedContraption extends Contraption { for (Axis axis : Iterate.axes) { if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis)) continue; - for (AbstractMinecart abstractMinecartEntity : world - .getEntitiesOfClass(AbstractMinecart.class, new AABB(pos))) { + for (AbstractMinecart abstractMinecartEntity : world.getEntitiesOfClass(AbstractMinecart.class, + new AABB(pos))) { if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity)) break; return true; @@ -156,14 +155,11 @@ public class MountedContraption extends Contraption { return true; } - @Override public void addExtraInventories(Entity cart) { - if (!(cart instanceof Container)) - return; - IItemHandlerModifiable handlerFromInv = new ContraptionInvWrapper(true, new InvWrapper((Container) cart)); - inventory = new ContraptionInvWrapper(handlerFromInv, inventory); + if (cart instanceof Container container) + storage.attachExternal(new ContraptionInvWrapper(true, new InvWrapper(container))); } - + @Override @OnlyIn(Dist.CLIENT) public ContraptionLighter makeLighter() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java index 6467efc58..5624adc33 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java @@ -23,13 +23,13 @@ public class ContraptionFluidPacket extends SimplePacketBase { this.localPos = localPos; this.containedFluid = containedFluid; } - + public ContraptionFluidPacket(FriendlyByteBuf buffer) { entityId = buffer.readInt(); localPos = buffer.readBlockPos(); containedFluid = FluidStack.readFromPacket(buffer); } - + @Override public void write(FriendlyByteBuf buffer) { buffer.writeInt(entityId); @@ -45,7 +45,7 @@ public class ContraptionFluidPacket extends SimplePacketBase { if (!(entityByID instanceof AbstractContraptionEntity)) return; AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; - contraptionEntity.getContraption().updateContainedFluid(localPos, containedFluid); + contraptionEntity.getContraption().handleContraptionFluidPacket(localPos, containedFluid); }); context.get() .setPacketHandled(true); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java index b9327e582..5928c0403 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java @@ -54,7 +54,6 @@ public class FunnelMovementBehaviour implements MovementBehaviour { else succ(context, pos); - } private void extract(MovementContext context, BlockPos pos) { @@ -64,23 +63,22 @@ public class FunnelMovementBehaviour implements MovementBehaviour { if (context.state.getValue(FunnelBlock.FACING) != Direction.DOWN) entityPos = entityPos.add(0, -.5f, 0); - if (!world.getBlockState(pos).getCollisionShape(world, pos).isEmpty()) - return;//only drop items if the target block is a empty space + if (!world.getBlockState(pos) + .getCollisionShape(world, pos) + .isEmpty()) + return; - if (!world.getEntitiesOfClass(ItemEntity.class, new AABB(new BlockPos(entityPos))).isEmpty()) - return;//don't drop items if there already are any in the target block space + if (!world.getEntitiesOfClass(ItemEntity.class, new AABB(new BlockPos(entityPos))) + .isEmpty()) + return; ItemStack filter = getFilter(context); int filterAmount = context.tileData.getInt("FilterAmount"); if (filterAmount <= 0) filterAmount = hasFilter ? AllConfigs.SERVER.logistics.defaultExtractionLimit.get() : 1; - ItemStack extract = ItemHelper.extract( - context.contraption.inventory, - s -> FilterItem.test(world, s, filter), - ItemHelper.ExtractionCountMode.UPTO, - filterAmount, - false); + ItemStack extract = ItemHelper.extract(context.contraption.getSharedInventory(), + s -> FilterItem.test(world, s, filter), ItemHelper.ExtractionCountMode.UPTO, filterAmount, false); if (extract.isEmpty()) return; @@ -88,12 +86,10 @@ public class FunnelMovementBehaviour implements MovementBehaviour { if (world.isClientSide) return; - - ItemEntity entity = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, extract); entity.setDeltaMovement(Vec3.ZERO); entity.setPickUpDelay(5); - world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 1/16f, .1f); + world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 1 / 16f, .1f); world.addFreshEntity(entity); } @@ -108,7 +104,8 @@ public class FunnelMovementBehaviour implements MovementBehaviour { ItemStack toInsert = item.getItem(); if (!filter.isEmpty() && !FilterItem.test(context.world, toInsert, filter)) continue; - ItemStack remainder = ItemHandlerHelper.insertItemStacked(context.contraption.inventory, toInsert, false); + ItemStack remainder = + ItemHandlerHelper.insertItemStacked(context.contraption.getSharedInventory(), toInsert, false); if (remainder.getCount() == toInsert.getCount()) continue; if (remainder.isEmpty()) { @@ -120,7 +117,7 @@ public class FunnelMovementBehaviour implements MovementBehaviour { item.setItem(remainder); } } - + @Override public boolean renderAsNormalTileEntity() { return true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java index 89acfea55..4ad5c089d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java @@ -55,9 +55,13 @@ public class TrackNodeLocation extends Vec3i { @Override public boolean equals(Object pOther) { - return super.equals(pOther) && pOther instanceof TrackNodeLocation tnl + return equalsIgnoreDim(pOther) && pOther instanceof TrackNodeLocation tnl && Objects.equals(tnl.dimension, dimension); } + + public boolean equalsIgnoreDim(Object pOther) { + return super.equals(pOther); + } @Override public int hashCode() { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index ad8af7f94..bd8b31733 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -20,6 +20,7 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableDouble; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.MountedStorageManager; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.logistics.trains.DimensionPalette; import com.simibubi.create.content.logistics.trains.TrackGraph; @@ -60,6 +61,7 @@ public class Carriage { public int bogeySpacing; public Couple bogeys; + public MountedStorageManager storage; CompoundTag serialisedEntity; Map serialisedPassengers; @@ -76,6 +78,7 @@ public class Carriage { this.presentConductors = Couple.create(false, false); this.serialisedPassengers = new HashMap<>(); this.entities = new HashMap<>(); + this.storage = new MountedStorageManager(); bogey1.setLeading(); bogey1.carriage = this; @@ -92,6 +95,7 @@ public class Carriage { } public void setContraption(Level level, CarriageContraption contraption) { + this.storage = null; CarriageContraptionEntity entity = CarriageContraptionEntity.create(level, contraption); entity.setCarriage(this); contraption.startMoving(level); @@ -177,7 +181,7 @@ public class Carriage { double moved = point.travel(graph, toMove, trackSelector, signalListener, point.ignoreTurns(), c -> { for (DimensionalCarriageEntity dce : entities.values()) - if (c.either(tnl -> tnl.equals(dce.pivot))) + if (c.either(tnl -> tnl.equalsIgnoreDim(dce.pivot))) return false; if (entities.size() > 1) { train.status.doublePortal(); @@ -220,7 +224,7 @@ public class Carriage { } public void updateConductors() { - if (anyAvailableEntity() == null || entities.size() > 1) + if (anyAvailableEntity() == null || entities.size() > 1 || serialisedPassengers.size() > 0) return; presentConductors.replace($ -> false); for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) { @@ -321,15 +325,6 @@ public class Carriage { : pivoted(dce, dimension, point, leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2); - int prevmin = dce.minAllowedLocalCoord(); - int prevmax = dce.maxAllowedLocalCoord(); - - dce.updateCutoff(leading); - if (prevmin != dce.minAllowedLocalCoord() || prevmax != dce.maxAllowedLocalCoord()) { - dce.updateRenderedCutoff(); - dce.updatePassengerLoadout(); - } - if (isOnTwoBogeys()) { dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, @@ -337,18 +332,27 @@ public class Carriage { dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() : pivoted(dce, dimension, point, leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); - continue; - } - if (dimension.equals(otherDimension)) { - dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); - continue; + } else { + if (dimension.equals(otherDimension)) { + dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); + } else { + dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() + : pivoted(dce, dimension, point, leadingWheelSpacing)); + dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() + : pivoted(dce, dimension, point, leadingWheelSpacing)); + } } + + int prevmin = dce.minAllowedLocalCoord(); + int prevmax = dce.maxAllowedLocalCoord(); + + dce.updateCutoff(leading); - dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); - dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); + if (prevmin != dce.minAllowedLocalCoord() || prevmax != dce.maxAllowedLocalCoord()) { + dce.updateRenderedCutoff(); + dce.updatePassengerLoadout(); + } } } @@ -595,6 +599,7 @@ public class Carriage { CompoundTag tag = new CompoundTag(); tag.putFloat("Cutoff", cutoff); tag.putInt("DiscardTicks", discardTicks); + storage.write(tag, false); if (pivot != null) tag.put("Pivot", pivot.write(null)); if (positionAnchor != null) @@ -607,6 +612,7 @@ public class Carriage { public void read(CompoundTag tag) { cutoff = tag.getFloat("Cutoff"); discardTicks = tag.getInt("DiscardTicks"); + storage.read(tag, null, false); if (tag.contains("Pivot")) pivot = TrackNodeLocation.read(tag.getCompound("Pivot"), null); if (positionAnchor != null) @@ -749,13 +755,13 @@ public class Carriage { Entity entity = this.entity.get(); if (!(entity instanceof CarriageContraptionEntity cce)) return; - if (!entity.level.isClientSide()) - return; Contraption contraption = cce.getContraption(); if (!(contraption instanceof CarriageContraption cc)) return; cc.portalCutoffMin = minAllowedLocalCoord(); cc.portalCutoffMax = maxAllowedLocalCoord(); + if (!entity.level.isClientSide()) + return; DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> invalidate(cce)); } @@ -776,12 +782,12 @@ public class Carriage { return; } + this.entity = new WeakReference<>(cce); + cce.setGraph(train.graph == null ? null : train.graph.id); cce.setCarriage(Carriage.this); cce.syncCarriage(); - this.entity = new WeakReference<>(cce); - if (level instanceof ServerLevel sl) sl.tryAddFreshEntityWithPassengers(entity); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java index 491168418..717e222b1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java @@ -14,6 +14,7 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.MountedStorageManager; import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; @@ -41,16 +42,21 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraft.world.phys.AABB; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandlerModifiable; public class CarriageContraption extends Contraption { private Direction assemblyDirection; private boolean forwardControls; private boolean backwardControls; + public Couple blazeBurnerConductors; public Map> conductorSeats; public ArrivalSoundQueue soundQueue; + protected MountedStorageManager storageProxy; + // during assembly only private int bogeys; private boolean sidewaysControls; @@ -116,6 +122,21 @@ public class CarriageContraption extends Contraption { return info.state.getValue(ControlsBlock.FACING) == direction.getOpposite(); } + public void swapStorageAfterAssembly(CarriageContraptionEntity cce) { + // Ensure that the entity does not hold its inventory data, because the global + // carriage manages it instead + Carriage carriage = cce.getCarriage(); + if (carriage.storage == null) { + carriage.storage = storage; + storage = new MountedStorageManager(); + } + storageProxy = carriage.storage; + } + + public void returnStorageForDisassembly(MountedStorageManager storage) { + this.storage = storage; + } + @Override protected boolean isAnchoringBlockAt(BlockPos pos) { return false; @@ -272,7 +293,7 @@ public class CarriageContraption extends Contraption { return !withinVisible(localPos) || atSeam(localPos); } - private boolean notInPortal() { + public boolean notInPortal() { return portalCutoffMin == Integer.MIN_VALUE && portalCutoffMax == Integer.MAX_VALUE; } @@ -294,4 +315,15 @@ public class CarriageContraption extends Contraption { return coord > portalCutoffMin && coord < portalCutoffMax; } + @Override + public IItemHandlerModifiable getSharedInventory() { + return storageProxy.getItems(); + } + + @Override + public IFluidHandler getSharedFluidTanks() { + return storageProxy.getFluids(); + } + + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java index e82385e50..a6d4808e7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java @@ -186,6 +186,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { dimensional.entity = new WeakReference<>(this); dimensional.pivot = null; carriage.updateContraptionAnchors(); + dimensional.updateRenderedCutoff(); } updateTrackGraph(); } else @@ -316,7 +317,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { @Override protected boolean isActorActive(MovementContext context, MovementBehaviour actor) { - return !getContraption().isHiddenInPortal(context.localPos) && super.isActorActive(context, actor); + return (contraption instanceof CarriageContraption cc) && (cc.notInPortal() || level.isClientSide()) + && super.isActorActive(context, actor); } @Override @@ -605,6 +607,13 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { this.carriage = carriage; this.trainId = carriage.train.id; this.carriageIndex = carriage.train.carriages.indexOf(carriage); + if (contraption instanceof CarriageContraption cc) + cc.swapStorageAfterAssembly(this); + + DimensionalCarriageEntity dimensional = carriage.getDimensional(level); + dimensional.pivot = null; + carriage.updateContraptionAnchors(); + dimensional.updateRenderedCutoff(); } public void setGraph(@Nullable UUID graphId) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 43c0d9b5f..8f0cd54d3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -541,6 +541,8 @@ public class Train { if (entity == null) return false; + if (entity.getContraption() instanceof CarriageContraption cc) + cc.returnStorageForDisassembly(carriage.storage); entity.setPos(Vec3 .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); entity.disassemble();