finished basic pipe logistics!

This commit is contained in:
Ellpeck 2020-04-14 18:51:43 +02:00
parent a11693632d
commit 6abfec9c94
7 changed files with 160 additions and 59 deletions

View file

@ -3,6 +3,7 @@ package de.ellpeck.prettypipes;
import net.minecraft.inventory.InventoryHelper; import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
@ -22,4 +23,9 @@ public final class Utility {
InventoryHelper.spawnItemStack(tile.getWorld(), pos.getX(), pos.getY(), pos.getZ(), stack); 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());
}
} }

View file

@ -2,6 +2,7 @@ package de.ellpeck.prettypipes.blocks.pipe;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.network.PipeItem;
import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.network.PipeNetwork;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.block.material.Material; 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) { public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (state.getBlock() != newState.getBlock()) { if (state.getBlock() != newState.getBlock()) {
PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, worldIn, pos); PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, worldIn, pos);
if (tile != null) if (tile != null) {
Utility.dropInventory(tile, tile.upgrades); Utility.dropInventory(tile, tile.upgrades);
for (PipeItem item : tile.items)
item.drop(worldIn);
}
PipeNetwork network = PipeNetwork.get(worldIn); PipeNetwork network = PipeNetwork.get(worldIn);
network.removeNode(pos); network.removeNode(pos);
network.onPipeChanged(pos, state); network.onPipeChanged(pos, state);

View file

@ -8,30 +8,70 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.item.BlockItem; 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.BlockPos;
import net.minecraft.util.math.MathHelper;
import java.util.Random;
public class PipeRenderer extends TileEntityRenderer<PipeTileEntity> { public class PipeRenderer extends TileEntityRenderer<PipeTileEntity> {
private final Random random = new Random();
public PipeRenderer(TileEntityRendererDispatcher disp) { public PipeRenderer(TileEntityRendererDispatcher disp) {
super(disp); super(disp);
} }
@Override @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(); BlockPos pos = tile.getPos();
for (PipeItem item : tile.items) { for (PipeItem item : tile.items) {
matrixStack.push(); 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) { if (item.stack.getItem() instanceof BlockItem) {
float scale = 0.65F; float scale = 0.7F;
matrixStack.scale(scale, scale, scale); matrixStack.scale(scale, scale, scale);
matrixStack.translate(0, -0.2F, 0); matrixStack.translate(0, -0.2F, 0);
} else { } else {
float scale = 0.4F; float scale = 0.45F;
matrixStack.scale(scale, scale, scale); 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(); 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;
}
} }

View file

@ -111,6 +111,10 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
} }
public BlockPos getAvailableDestination(ItemStack stack) { 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()) { for (Direction dir : Direction.values()) {
IItemHandler handler = this.getItemHandler(dir); IItemHandler handler = this.getItemHandler(dir);
if (handler == null) if (handler == null)
@ -128,6 +132,6 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
TileEntity tile = this.world.getTileEntity(this.pos.offset(dir)); TileEntity tile = this.world.getTileEntity(this.pos.offset(dir));
if (tile == null) if (tile == null)
return null; return null;
return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(null); return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dir.getOpposite()).orElse(null);
} }
} }

View file

@ -22,7 +22,6 @@ public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable
public BlockPos startPipe; public BlockPos startPipe;
public BlockPos endPipe; public BlockPos endPipe;
public final List<BlockPos> pipes = new ArrayList<>(); public final List<BlockPos> pipes = new ArrayList<>();
private final Map<Integer, PipeTileEntity> tileCache = new HashMap<>();
public NetworkEdge() { public NetworkEdge() {
} }
@ -31,15 +30,6 @@ public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable
this.deserializeNBT(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 @Override
public CompoundNBT serializeNBT() { public CompoundNBT serializeNBT() {
CompoundNBT nbt = new CompoundNBT(); CompoundNBT nbt = new CompoundNBT();

View file

@ -1,36 +1,47 @@
package de.ellpeck.prettypipes.network; package de.ellpeck.prettypipes.network;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity; import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; 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.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.INBTSerializable; 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 org.jgrapht.GraphPath;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
public class PipeItem implements INBTSerializable<CompoundNBT> { public class PipeItem implements INBTSerializable<CompoundNBT> {
public static final int PIPE_TIME = 40; public static final int PIPE_TIME = 20;
public ItemStack stack; public ItemStack stack;
public float x; public float x;
public float y; public float y;
public float z; public float z;
public float lastX;
public float lastY;
public float lastZ;
private final List<NetworkEdge> pathEdges; private final List<BlockPos> path;
private BlockPos startPipe; private BlockPos startPipe;
private BlockPos destPipe; private BlockPos destPipe;
private BlockPos destInventory; private BlockPos destInventory;
private int pipeTimer; private int pipeTimer;
private int currentEdge;
private int currentTile; private int currentTile;
public PipeItem(ItemStack stack, BlockPos startPipe, BlockPos startInventory, BlockPos destPipe, BlockPos destInventory, GraphPath<BlockPos, NetworkEdge> path) { public PipeItem(ItemStack stack, BlockPos startPipe, BlockPos startInventory, BlockPos destPipe, BlockPos destInventory, GraphPath<BlockPos, NetworkEdge> path) {
@ -38,14 +49,14 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
this.startPipe = startPipe; this.startPipe = startPipe;
this.destPipe = destPipe; this.destPipe = destPipe;
this.destInventory = destInventory; this.destInventory = destInventory;
this.pathEdges = path.getEdgeList(); this.path = compilePath(path);
this.x = MathHelper.lerp(0.5F, startInventory.getX(), startPipe.getX()) + 0.5F; 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.y = MathHelper.lerp(0.5F, startInventory.getY(), startPipe.getY()) + 0.5F;
this.z = MathHelper.lerp(0.5F, startInventory.getZ(), startPipe.getZ()) + 0.5F; this.z = MathHelper.lerp(0.5F, startInventory.getZ(), startPipe.getZ()) + 0.5F;
} }
public PipeItem(CompoundNBT nbt) { public PipeItem(CompoundNBT nbt) {
this.pathEdges = new ArrayList<>(); this.path = new ArrayList<>();
this.deserializeNBT(nbt); this.deserializeNBT(nbt);
} }
@ -57,8 +68,16 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
currPipe.items.remove(this); currPipe.items.remove(this);
PipeTileEntity next = this.getNextTile(currPipe, true); PipeTileEntity next = this.getNextTile(currPipe, true);
if (next == null) { if (next == null) {
// ..or store in our destination container if there is no next one if (!currPipe.getWorld().isRemote) {
this.store(currPipe); 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; return;
} else { } else {
next.items.add(this); next.items.add(this);
@ -69,7 +88,14 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
// we're past the start of the pipe, so move to the center of the next pipe // we're past the start of the pipe, so move to the center of the next pipe
PipeTileEntity next = this.getNextTile(currPipe, false); PipeTileEntity next = this.getNextTile(currPipe, false);
if (next == null) { if (next == null) {
if (this.reachedDestination()) {
goalPos = this.destInventory; goalPos = this.destInventory;
} else {
currPipe.items.remove(this);
if (!currPipe.getWorld().isRemote)
this.onPathObstructed(currPipe);
return;
}
} else { } else {
goalPos = next.getPos(); goalPos = next.getPos();
} }
@ -78,6 +104,10 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
goalPos = currPipe.getPos(); goalPos = currPipe.getPos();
} }
this.lastX = this.x;
this.lastY = this.y;
this.lastZ = this.z;
float speed = 1 / (float) PIPE_TIME; 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); 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(); dist = dist.normalize();
@ -86,35 +116,39 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
this.z += dist.z * speed; this.z += dist.z * speed;
} }
private void store(PipeTileEntity currPipe) { private void onPathObstructed(PipeTileEntity currPipe) {
if (currPipe.getWorld().isRemote) // TODO when the path is obstructed, try to turn back home first
return; this.drop(currPipe.getWorld());
// TODO store in destination }
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) { private PipeTileEntity getNextTile(PipeTileEntity currPipe, boolean progress) {
NetworkEdge edge = this.pathEdges.get(this.currentEdge); if (this.path.size() <= this.currentTile + 1)
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; return null;
edge = this.pathEdges.get(this.currentEdge + 1); BlockPos pos = this.path.get(this.currentTile + 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) if (progress)
this.currentEdge++; this.currentTile++;
} PipeNetwork network = PipeNetwork.get(currPipe.getWorld());
if (progress) return network.getPipe(pos);
this.currentTile = currTile;
// TODO invert the current tile index if the current edge is the other way around
return edge.getPipe(currPipe.getWorld(), currTile);
} }
@Override @Override
@ -125,14 +159,13 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
nbt.put("dest_pipe", NBTUtil.writeBlockPos(this.destPipe)); nbt.put("dest_pipe", NBTUtil.writeBlockPos(this.destPipe));
nbt.put("dest_inv", NBTUtil.writeBlockPos(this.destInventory)); nbt.put("dest_inv", NBTUtil.writeBlockPos(this.destInventory));
nbt.putInt("timer", this.pipeTimer); nbt.putInt("timer", this.pipeTimer);
nbt.putInt("edge", this.currentEdge);
nbt.putInt("tile", this.currentTile); nbt.putInt("tile", this.currentTile);
nbt.putFloat("x", this.x); nbt.putFloat("x", this.x);
nbt.putFloat("y", this.y); nbt.putFloat("y", this.y);
nbt.putFloat("z", this.z); nbt.putFloat("z", this.z);
ListNBT list = new ListNBT(); ListNBT list = new ListNBT();
for (NetworkEdge edge : this.pathEdges) for (BlockPos pos : this.path)
list.add(edge.serializeNBT()); list.add(NBTUtil.writeBlockPos(pos));
nbt.put("path", list); nbt.put("path", list);
return nbt; return nbt;
} }
@ -144,14 +177,39 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
this.destPipe = NBTUtil.readBlockPos(nbt.getCompound("dest_pipe")); this.destPipe = NBTUtil.readBlockPos(nbt.getCompound("dest_pipe"));
this.destInventory = NBTUtil.readBlockPos(nbt.getCompound("dest_inv")); this.destInventory = NBTUtil.readBlockPos(nbt.getCompound("dest_inv"));
this.pipeTimer = nbt.getInt("timer"); this.pipeTimer = nbt.getInt("timer");
this.currentEdge = nbt.getInt("edge");
this.currentTile = nbt.getInt("tile"); this.currentTile = nbt.getInt("tile");
this.x = nbt.getFloat("x"); this.x = nbt.getFloat("x");
this.y = nbt.getFloat("y"); this.y = nbt.getFloat("y");
this.z = nbt.getFloat("z"); this.z = nbt.getFloat("z");
this.pathEdges.clear(); this.path.clear();
ListNBT list = nbt.getList("path", Constants.NBT.TAG_COMPOUND); ListNBT list = nbt.getList("path", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < list.size(); i++) 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<BlockPos> compilePath(GraphPath<BlockPos, NetworkEdge> path) {
Graph<BlockPos, NetworkEdge> graph = path.getGraph();
List<BlockPos> ret = new ArrayList<>();
List<BlockPos> 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<Integer> 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;
} }
} }

View file

@ -118,7 +118,6 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
BlockPos dest = pipe.getAvailableDestination(stack); BlockPos dest = pipe.getAvailableDestination(stack);
if (dest != null) { if (dest != null) {
GraphPath<BlockPos, NetworkEdge> path = this.dijkstra.getPath(startPipePos, pipe.getPos()); GraphPath<BlockPos, NetworkEdge> 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); PipeItem item = new PipeItem(stack.copy(), startPipePos, originInv, pipe.getPos(), dest, path);
startPipe.items.add(item); startPipe.items.add(item);
PacketHandler.sendToAllLoaded(this.world, startPipePos, new PacketItemEnterPipe(startPipePos, item)); PacketHandler.sendToAllLoaded(this.world, startPipePos, new PacketItemEnterPipe(startPipePos, item));