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.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());
}
}

View file

@ -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);

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.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<PipeTileEntity> {
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;
}
}

View file

@ -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);
}
}

View file

@ -22,24 +22,14 @@ public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable
public BlockPos startPipe;
public BlockPos endPipe;
public final List<BlockPos> pipes = new ArrayList<>();
private final Map<Integer, PipeTileEntity> 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();

View file

@ -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<CompoundNBT> {
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<NetworkEdge> pathEdges;
private final List<BlockPos> 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<BlockPos, NetworkEdge> path) {
@ -38,14 +49,14 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
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<CompoundNBT> {
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<CompoundNBT> {
// 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) {
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<CompoundNBT> {
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<CompoundNBT> {
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)
if (this.path.size() <= this.currentTile + 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;
BlockPos pos = this.path.get(this.currentTile + 1);
if (progress)
this.currentEdge++;
}
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<CompoundNBT> {
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<CompoundNBT> {
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<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);
if (dest != null) {
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);
startPipe.items.add(item);
PacketHandler.sendToAllLoaded(this.world, startPipePos, new PacketItemEnterPipe(startPipePos, item));