diff --git a/src/main/java/de/ellpeck/prettypipes/Utility.java b/src/main/java/de/ellpeck/prettypipes/Utility.java index 4186b74..c0d3967 100644 --- a/src/main/java/de/ellpeck/prettypipes/Utility.java +++ b/src/main/java/de/ellpeck/prettypipes/Utility.java @@ -3,6 +3,7 @@ package de.ellpeck.prettypipes; import net.minecraft.inventory.InventoryHelper; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.items.IItemHandler; @@ -22,4 +23,9 @@ public final class Utility { InventoryHelper.spawnItemStack(tile.getWorld(), pos.getX(), pos.getY(), pos.getZ(), stack); } } + + public static Direction getDirectionFromOffset(BlockPos pos, BlockPos other) { + BlockPos diff = pos.subtract(other); + return Direction.getFacingFromVector(diff.getX(), diff.getY(), diff.getZ()); + } } diff --git a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeBlock.java b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeBlock.java index e00087a..64514b7 100644 --- a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeBlock.java @@ -2,6 +2,7 @@ package de.ellpeck.prettypipes.blocks.pipe; import com.google.common.collect.ImmutableMap; import de.ellpeck.prettypipes.Utility; +import de.ellpeck.prettypipes.network.PipeItem; import de.ellpeck.prettypipes.network.PipeNetwork; import net.minecraft.block.*; import net.minecraft.block.material.Material; @@ -182,8 +183,11 @@ public class PipeBlock extends ContainerBlock { public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, worldIn, pos); - if (tile != null) + if (tile != null) { Utility.dropInventory(tile, tile.upgrades); + for (PipeItem item : tile.items) + item.drop(worldIn); + } PipeNetwork network = PipeNetwork.get(worldIn); network.removeNode(pos); network.onPipeChanged(pos, state); diff --git a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeRenderer.java b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeRenderer.java index 8fb6526..11e68c9 100644 --- a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeRenderer.java +++ b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeRenderer.java @@ -8,30 +8,70 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; + +import java.util.Random; public class PipeRenderer extends TileEntityRenderer { + private final Random random = new Random(); + public PipeRenderer(TileEntityRendererDispatcher disp) { super(disp); } @Override - public void render(PipeTileEntity tile, float v, MatrixStack matrixStack, IRenderTypeBuffer iRenderTypeBuffer, int i, int i1) { + public void render(PipeTileEntity tile, float v, MatrixStack matrixStack, IRenderTypeBuffer iRenderTypeBuffer, int k, int i1) { BlockPos pos = tile.getPos(); for (PipeItem item : tile.items) { matrixStack.push(); - matrixStack.translate(item.x - pos.getX(), item.y - pos.getY(), item.z - pos.getZ()); + matrixStack.translate( + MathHelper.lerp(v, item.lastX, item.x) - pos.getX(), + MathHelper.lerp(v, item.lastY, item.y) - pos.getY(), + MathHelper.lerp(v, item.lastZ, item.z) - pos.getZ()); + if (item.stack.getItem() instanceof BlockItem) { - float scale = 0.65F; + float scale = 0.7F; matrixStack.scale(scale, scale, scale); matrixStack.translate(0, -0.2F, 0); } else { - float scale = 0.4F; + float scale = 0.45F; matrixStack.scale(scale, scale, scale); + matrixStack.translate(0, -0.1F, 0); + } + + this.random.setSeed(Item.getIdFromItem(item.stack.getItem()) + item.stack.getDamage()); + int amount = this.getModelCount(item.stack); + + for (int i = 0; i < amount; i++) { + matrixStack.push(); + if (amount > 1) { + matrixStack.translate( + (this.random.nextFloat() * 2.0F - 1.0F) * 0.25F * 0.5F, + (this.random.nextFloat() * 2.0F - 1.0F) * 0.25F * 0.5F, + (this.random.nextFloat() * 2.0F - 1.0F) * 0.25F * 0.5F); + } + Minecraft.getInstance().getItemRenderer().renderItem(item.stack, ItemCameraTransforms.TransformType.GROUND, k, i1, matrixStack, iRenderTypeBuffer); + matrixStack.pop(); } - Minecraft.getInstance().getItemRenderer().renderItem(item.stack, ItemCameraTransforms.TransformType.GROUND, i, i1, matrixStack, iRenderTypeBuffer); matrixStack.pop(); } } + + protected int getModelCount(ItemStack stack) { + int i = 1; + if (stack.getCount() > 48) { + i = 5; + } else if (stack.getCount() > 32) { + i = 4; + } else if (stack.getCount() > 16) { + i = 3; + } else if (stack.getCount() > 1) { + i = 2; + } + return i; + } } 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 aa6e712..baebcfa 100644 --- a/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/blocks/pipe/PipeTileEntity.java @@ -111,6 +111,10 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide } public BlockPos getAvailableDestination(ItemStack stack) { + for (int i = 0; i < this.upgrades.getSlots(); i++) { + if (this.upgrades.getStackInSlot(i).getItem() == Registry.extractionUpgradeItem) + return null; + } for (Direction dir : Direction.values()) { IItemHandler handler = this.getItemHandler(dir); if (handler == null) @@ -128,6 +132,6 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide TileEntity tile = this.world.getTileEntity(this.pos.offset(dir)); if (tile == null) return null; - return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(null); + return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dir.getOpposite()).orElse(null); } } diff --git a/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java b/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java index ef1504a..0b44451 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java +++ b/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java @@ -22,24 +22,14 @@ public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable public BlockPos startPipe; public BlockPos endPipe; public final List pipes = new ArrayList<>(); - private final Map tileCache = new HashMap<>(); - public NetworkEdge(){ + public NetworkEdge() { } - public NetworkEdge(CompoundNBT nbt){ + public NetworkEdge(CompoundNBT nbt) { this.deserializeNBT(nbt); } - public PipeTileEntity getPipe(World world, int index) { - PipeTileEntity tile = this.tileCache.get(index); - if (tile == null || tile.isRemoved()) { - tile = Utility.getTileEntity(PipeTileEntity.class, world, this.pipes.get(index)); - this.tileCache.put(index, tile); - } - return tile; - } - @Override public CompoundNBT serializeNBT() { CompoundNBT nbt = new CompoundNBT(); diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java index f709a67..ed1e8c0 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java @@ -1,36 +1,47 @@ package de.ellpeck.prettypipes.network; +import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity; +import net.minecraft.entity.item.ItemEntity; 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.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import org.jgrapht.Graph; import org.jgrapht.GraphPath; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; public class PipeItem implements INBTSerializable { - public static final int PIPE_TIME = 40; + public static final int PIPE_TIME = 20; public ItemStack stack; public float x; public float y; public float z; + public float lastX; + public float lastY; + public float lastZ; - private final List pathEdges; + private final List path; private BlockPos startPipe; private BlockPos destPipe; private BlockPos destInventory; private int pipeTimer; - private int currentEdge; private int currentTile; public PipeItem(ItemStack stack, BlockPos startPipe, BlockPos startInventory, BlockPos destPipe, BlockPos destInventory, GraphPath path) { @@ -38,14 +49,14 @@ public class PipeItem implements INBTSerializable { this.startPipe = startPipe; this.destPipe = destPipe; this.destInventory = destInventory; - this.pathEdges = path.getEdgeList(); + this.path = compilePath(path); 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; } public PipeItem(CompoundNBT nbt) { - this.pathEdges = new ArrayList<>(); + this.path = new ArrayList<>(); this.deserializeNBT(nbt); } @@ -57,8 +68,16 @@ public class PipeItem implements INBTSerializable { currPipe.items.remove(this); PipeTileEntity next = this.getNextTile(currPipe, true); if (next == null) { - // ..or store in our destination container if there is no next one - this.store(currPipe); + if (!currPipe.getWorld().isRemote) { + if (this.reachedDestination()) { + // ..or store in our destination container if we reached our destination + this.stack = this.store(currPipe); + if (!this.stack.isEmpty()) + this.onPathObstructed(currPipe); + } else { + this.onPathObstructed(currPipe); + } + } return; } else { next.items.add(this); @@ -69,7 +88,14 @@ public class PipeItem implements INBTSerializable { // we're past the start of the pipe, so move to the center of the next pipe PipeTileEntity next = this.getNextTile(currPipe, false); if (next == null) { - goalPos = this.destInventory; + if (this.reachedDestination()) { + goalPos = this.destInventory; + } else { + currPipe.items.remove(this); + if (!currPipe.getWorld().isRemote) + this.onPathObstructed(currPipe); + return; + } } else { goalPos = next.getPos(); } @@ -78,6 +104,10 @@ public class PipeItem implements INBTSerializable { goalPos = currPipe.getPos(); } + this.lastX = this.x; + this.lastY = this.y; + this.lastZ = this.z; + float speed = 1 / (float) PIPE_TIME; Vec3d dist = new Vec3d(goalPos.getX() + 0.5F - this.x, goalPos.getY() + 0.5F - this.y, goalPos.getZ() + 0.5F - this.z); dist = dist.normalize(); @@ -86,35 +116,39 @@ public class PipeItem implements INBTSerializable { this.z += dist.z * speed; } - private void store(PipeTileEntity currPipe) { - if (currPipe.getWorld().isRemote) - return; - // TODO store in destination + private void onPathObstructed(PipeTileEntity currPipe) { + // TODO when the path is obstructed, try to turn back home first + this.drop(currPipe.getWorld()); + } + + public void drop(World world) { + ItemEntity item = new ItemEntity(world, this.x, this.y, this.z, this.stack.copy()); + item.world.addEntity(item); + } + + private ItemStack store(PipeTileEntity currPipe) { + TileEntity tile = currPipe.getWorld().getTileEntity(this.destInventory); + if (tile == null) + return this.stack; + Direction dir = Utility.getDirectionFromOffset(this.destPipe, this.destInventory); + IItemHandler handler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dir).orElse(null); + if (handler == null) + return this.stack; + return ItemHandlerHelper.insertItemStacked(handler, this.stack, false); + } + + private boolean reachedDestination() { + return this.currentTile >= this.path.size() - 1; } private PipeTileEntity getNextTile(PipeTileEntity currPipe, boolean progress) { - NetworkEdge edge = this.pathEdges.get(this.currentEdge); - int currTile = this.currentTile; - if (edge.pipes.size() > currTile + 1) { - currTile++; - } else { - // are we at the end of our path? - if (this.pathEdges.size() <= this.currentEdge + 1) - return null; - edge = this.pathEdges.get(this.currentEdge + 1); - // we're setting the current tile to 1 since the 0th index of - // the next edge is also the last index of the current edge - currTile = 1; - if (progress) - this.currentEdge++; - } + if (this.path.size() <= this.currentTile + 1) + return null; + BlockPos pos = this.path.get(this.currentTile + 1); if (progress) - this.currentTile = currTile; - - // TODO invert the current tile index if the current edge is the other way around - - - return edge.getPipe(currPipe.getWorld(), currTile); + this.currentTile++; + PipeNetwork network = PipeNetwork.get(currPipe.getWorld()); + return network.getPipe(pos); } @Override @@ -125,14 +159,13 @@ public class PipeItem implements INBTSerializable { nbt.put("dest_pipe", NBTUtil.writeBlockPos(this.destPipe)); nbt.put("dest_inv", NBTUtil.writeBlockPos(this.destInventory)); nbt.putInt("timer", this.pipeTimer); - nbt.putInt("edge", this.currentEdge); nbt.putInt("tile", this.currentTile); nbt.putFloat("x", this.x); nbt.putFloat("y", this.y); nbt.putFloat("z", this.z); ListNBT list = new ListNBT(); - for (NetworkEdge edge : this.pathEdges) - list.add(edge.serializeNBT()); + for (BlockPos pos : this.path) + list.add(NBTUtil.writeBlockPos(pos)); nbt.put("path", list); return nbt; } @@ -144,14 +177,39 @@ public class PipeItem implements INBTSerializable { this.destPipe = NBTUtil.readBlockPos(nbt.getCompound("dest_pipe")); this.destInventory = NBTUtil.readBlockPos(nbt.getCompound("dest_inv")); this.pipeTimer = nbt.getInt("timer"); - this.currentEdge = nbt.getInt("edge"); this.currentTile = nbt.getInt("tile"); this.x = nbt.getFloat("x"); this.y = nbt.getFloat("y"); this.z = nbt.getFloat("z"); - this.pathEdges.clear(); + this.path.clear(); ListNBT list = nbt.getList("path", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < list.size(); i++) - this.pathEdges.add(new NetworkEdge(list.getCompound(i))); + this.path.add(NBTUtil.readBlockPos(list.getCompound(i))); + } + + private static List compilePath(GraphPath path) { + Graph graph = path.getGraph(); + List ret = new ArrayList<>(); + List nodes = path.getVertexList(); + for (int i = 0; i < nodes.size() - 1; i++) { + BlockPos first = nodes.get(i); + BlockPos second = nodes.get(i + 1); + NetworkEdge edge = graph.getEdge(first, second); + Consumer add = j -> { + BlockPos pos = edge.pipes.get(j); + if (!ret.contains(pos)) + ret.add(pos); + }; + // if the edge is the other way around, we need to loop through tiles + // the other way also + if (!graph.getEdgeSource(edge).equals(first)) { + for (int j = edge.pipes.size() - 1; j >= 0; j--) + add.accept(j); + } else { + for (int j = 0; j < edge.pipes.size(); j++) + add.accept(j); + } + } + return ret; } } diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index f474525..41c2d77 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -118,7 +118,6 @@ public class PipeNetwork implements ICapabilitySerializable { BlockPos dest = pipe.getAvailableDestination(stack); if (dest != null) { GraphPath path = this.dijkstra.getPath(startPipePos, pipe.getPos()); - System.out.println("Found path " + path + " from " + startPipePos + " to " + 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));