diff --git a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java index baebcfa..bee8121 100644 --- a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java @@ -25,16 +25,11 @@ import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; -import org.jgrapht.GraphPath; -import org.jgrapht.alg.interfaces.ShortestPathAlgorithm; -import org.jgrapht.alg.interfaces.ShortestPathAlgorithm.SingleSourcePaths; -import org.jgrapht.traverse.ClosestFirstIterator; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import java.util.function.Predicate; public class PipeTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity { @@ -81,8 +76,18 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide super.read(compound); } + @Override + public CompoundNBT getUpdateTag() { + // by default, this is just writeInternal, but we + // want to sync the current pipe items on load too + return this.write(new CompoundNBT()); + } + @Override public void tick() { + if (!this.world.isAreaLoaded(this.pos, 1)) + return; + for (int i = this.items.size() - 1; i >= 0; i--) this.items.get(i).updateInPipe(this); diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java index ed1e8c0..1d9401e 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java @@ -37,19 +37,18 @@ public class PipeItem implements INBTSerializable { public float lastY; public float lastZ; - private final List path; + private List path; private BlockPos startPipe; + private BlockPos startInventory; private BlockPos destPipe; private BlockPos destInventory; private int pipeTimer; private int currentTile; + private boolean dropOnObstruction; - public PipeItem(ItemStack stack, BlockPos startPipe, BlockPos startInventory, BlockPos destPipe, BlockPos destInventory, GraphPath path) { + public PipeItem(ItemStack stack, BlockPos startPipe, BlockPos startInventory) { this.stack = stack; - this.startPipe = startPipe; - this.destPipe = destPipe; - this.destInventory = destInventory; - this.path = compilePath(path); + this.startInventory = startInventory; this.x = MathHelper.lerp(0.5F, startInventory.getX(), startPipe.getX()) + 0.5F; this.y = MathHelper.lerp(0.5F, startInventory.getY(), startPipe.getY()) + 0.5F; this.z = MathHelper.lerp(0.5F, startInventory.getZ(), startPipe.getZ()) + 0.5F; @@ -60,6 +59,15 @@ public class PipeItem implements INBTSerializable { this.deserializeNBT(nbt); } + public void setDestination(BlockPos startPipe, BlockPos destPipe, BlockPos destInventory, GraphPath path) { + this.startPipe = startPipe; + this.destPipe = destPipe; + this.destInventory = destInventory; + this.path = compilePath(path); + this.currentTile = 0; + this.pipeTimer = 0; + } + public void updateInPipe(PipeTileEntity currPipe) { this.pipeTimer++; BlockPos goalPos; @@ -73,9 +81,9 @@ public class PipeItem implements INBTSerializable { // ..or store in our destination container if we reached our destination this.stack = this.store(currPipe); if (!this.stack.isEmpty()) - this.onPathObstructed(currPipe); + this.onPathObstructed(currPipe, true); } else { - this.onPathObstructed(currPipe); + this.onPathObstructed(currPipe, false); } } return; @@ -93,7 +101,7 @@ public class PipeItem implements INBTSerializable { } else { currPipe.items.remove(this); if (!currPipe.getWorld().isRemote) - this.onPathObstructed(currPipe); + this.onPathObstructed(currPipe, false); return; } } else { @@ -116,8 +124,14 @@ public class PipeItem implements INBTSerializable { this.z += dist.z * speed; } - private void onPathObstructed(PipeTileEntity currPipe) { - // TODO when the path is obstructed, try to turn back home first + private void onPathObstructed(PipeTileEntity currPipe, boolean tryReturn) { + if (!this.dropOnObstruction && tryReturn) { + PipeNetwork network = PipeNetwork.get(currPipe.getWorld()); + if (network.routeItemToLocation(currPipe.getPos(), this.startPipe, this.startInventory, () -> this)) { + this.dropOnObstruction = true; + return; + } + } this.drop(currPipe.getWorld()); } @@ -156,8 +170,10 @@ public class PipeItem implements INBTSerializable { CompoundNBT nbt = new CompoundNBT(); nbt.put("stack", this.stack.serializeNBT()); nbt.put("start_pipe", NBTUtil.writeBlockPos(this.startPipe)); + nbt.put("start_inventory", NBTUtil.writeBlockPos(this.startInventory)); nbt.put("dest_pipe", NBTUtil.writeBlockPos(this.destPipe)); nbt.put("dest_inv", NBTUtil.writeBlockPos(this.destInventory)); + nbt.putBoolean("drop_on_obstruction", this.dropOnObstruction); nbt.putInt("timer", this.pipeTimer); nbt.putInt("tile", this.currentTile); nbt.putFloat("x", this.x); @@ -174,8 +190,10 @@ public class PipeItem implements INBTSerializable { public void deserializeNBT(CompoundNBT nbt) { this.stack = ItemStack.read(nbt.getCompound("stack")); this.startPipe = NBTUtil.readBlockPos(nbt.getCompound("start_pipe")); + this.startInventory = NBTUtil.readBlockPos(nbt.getCompound("start_inventory")); this.destPipe = NBTUtil.readBlockPos(nbt.getCompound("dest_pipe")); this.destInventory = NBTUtil.readBlockPos(nbt.getCompound("dest_inv")); + this.dropOnObstruction = nbt.getBoolean("drop_on_obstruction"); this.pipeTimer = nbt.getInt("timer"); this.currentTile = nbt.getInt("tile"); this.x = nbt.getFloat("x"); diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index 41c2d77..daf9a17 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -1,21 +1,17 @@ package de.ellpeck.prettypipes.network; -import com.google.common.collect.Sets; import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.blocks.pipe.PipeBlock; import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity; import de.ellpeck.prettypipes.packets.PacketHandler; import de.ellpeck.prettypipes.packets.PacketItemEnterPipe; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.NBTUtil; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; -import net.minecraft.util.Tuple; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; @@ -23,8 +19,6 @@ import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.LazyOptional; import org.jgrapht.GraphPath; -import org.jgrapht.alg.interfaces.ShortestPathAlgorithm; -import org.jgrapht.alg.interfaces.ShortestPathAlgorithm.SingleSourcePaths; import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.SimpleWeightedGraph; import org.jgrapht.traverse.ClosestFirstIterator; @@ -35,6 +29,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; public class PipeNetwork implements ICapabilitySerializable { @@ -104,8 +99,14 @@ public class PipeNetwork implements ICapabilitySerializable { } public boolean tryInsertItem(BlockPos startPipePos, BlockPos originInv, ItemStack stack) { + return this.routeItem(startPipePos, stack, () -> new PipeItem(stack, startPipePos, originInv)); + } + + public boolean routeItem(BlockPos startPipePos, ItemStack stack, Supplier itemSupplier) { if (!this.isNode(startPipePos)) return false; + if (!this.world.isBlockLoaded(startPipePos)) + return false; PipeTileEntity startPipe = this.getPipe(startPipePos); if (startPipe == null) return false; @@ -116,17 +117,29 @@ public class PipeNetwork implements ICapabilitySerializable { if (pipe == startPipe) continue; BlockPos dest = pipe.getAvailableDestination(stack); - if (dest != null) { - GraphPath path = this.dijkstra.getPath(startPipePos, pipe.getPos()); - PipeItem item = new PipeItem(stack.copy(), startPipePos, originInv, pipe.getPos(), dest, path); - startPipe.items.add(item); - PacketHandler.sendToAllLoaded(this.world, startPipePos, new PacketItemEnterPipe(startPipePos, item)); - return true; - } + if (dest != null) + return this.routeItemToLocation(startPipePos, pipe.getPos(), dest, itemSupplier); } return false; } + public boolean routeItemToLocation(BlockPos startPipePos, BlockPos destPipe, BlockPos destInventory, Supplier itemSupplier) { + if (!this.isNode(startPipePos)) + return false; + if (!this.world.isBlockLoaded(startPipePos)) + return false; + PipeTileEntity startPipe = this.getPipe(startPipePos); + if (startPipe == null) + return false; + GraphPath path = this.dijkstra.getPath(startPipePos, destPipe); + PipeItem item = itemSupplier.get(); + item.setDestination(startPipePos, destPipe, destInventory, path); + if (!startPipe.items.contains(item)) + startPipe.items.add(item); + PacketHandler.sendToAllLoaded(this.world, startPipePos, new PacketItemEnterPipe(startPipePos, item)); + return true; + } + public PipeTileEntity getPipe(BlockPos pos) { PipeTileEntity tile = this.tileCache.get(pos); if (tile == null || tile.isRemoved()) {