mirror of
https://github.com/Ellpeck/PrettyPipes.git
synced 2024-11-22 19:58:35 +01:00
pipe movement, part 1
This commit is contained in:
parent
0a674ba1b5
commit
a11693632d
8 changed files with 434 additions and 21 deletions
|
@ -1,12 +1,10 @@
|
||||||
package de.ellpeck.prettypipes;
|
package de.ellpeck.prettypipes;
|
||||||
|
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeBlock;
|
import de.ellpeck.prettypipes.blocks.pipe.*;
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeContainer;
|
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeGui;
|
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
|
|
||||||
import de.ellpeck.prettypipes.items.ExtractionUpgradeItem;
|
import de.ellpeck.prettypipes.items.ExtractionUpgradeItem;
|
||||||
import de.ellpeck.prettypipes.items.WrenchItem;
|
import de.ellpeck.prettypipes.items.WrenchItem;
|
||||||
import de.ellpeck.prettypipes.network.PipeNetwork;
|
import de.ellpeck.prettypipes.network.PipeNetwork;
|
||||||
|
import de.ellpeck.prettypipes.packets.PacketHandler;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.gui.ScreenManager;
|
import net.minecraft.client.gui.ScreenManager;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
@ -17,7 +15,6 @@ import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemGroup;
|
import net.minecraft.item.ItemGroup;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.INBT;
|
import net.minecraft.nbt.INBT;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraftforge.common.capabilities.Capability;
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
@ -26,6 +23,7 @@ import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
import net.minecraftforge.common.extensions.IForgeContainerType;
|
import net.minecraftforge.common.extensions.IForgeContainerType;
|
||||||
import net.minecraftforge.event.RegistryEvent;
|
import net.minecraftforge.event.RegistryEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
|
@ -103,10 +101,12 @@ public final class Registry {
|
||||||
|
|
||||||
}
|
}
|
||||||
}, () -> null);
|
}, () -> null);
|
||||||
|
PacketHandler.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupClient(FMLClientSetupEvent event) {
|
public static void setupClient(FMLClientSetupEvent event) {
|
||||||
RenderTypeLookup.setRenderLayer(pipeBlock, RenderType.cutout());
|
RenderTypeLookup.setRenderLayer(pipeBlock, RenderType.cutout());
|
||||||
|
ClientRegistry.bindTileEntityRenderer(pipeTileEntity, PipeRenderer::new);
|
||||||
ScreenManager.registerFactory(pipeContainer, PipeGui::new);
|
ScreenManager.registerFactory(pipeContainer, PipeGui::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package de.ellpeck.prettypipes.blocks.pipe;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import de.ellpeck.prettypipes.network.PipeItem;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
|
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.util.math.BlockPos;
|
||||||
|
|
||||||
|
public class PipeRenderer extends TileEntityRenderer<PipeTileEntity> {
|
||||||
|
|
||||||
|
public PipeRenderer(TileEntityRendererDispatcher disp) {
|
||||||
|
super(disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(PipeTileEntity tile, float v, MatrixStack matrixStack, IRenderTypeBuffer iRenderTypeBuffer, int i, 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());
|
||||||
|
if (item.stack.getItem() instanceof BlockItem) {
|
||||||
|
float scale = 0.65F;
|
||||||
|
matrixStack.scale(scale, scale, scale);
|
||||||
|
matrixStack.translate(0, -0.2F, 0);
|
||||||
|
} else {
|
||||||
|
float scale = 0.4F;
|
||||||
|
matrixStack.scale(scale, scale, scale);
|
||||||
|
}
|
||||||
|
Minecraft.getInstance().getItemRenderer().renderItem(item.stack, ItemCameraTransforms.TransformType.GROUND, i, i1, matrixStack, iRenderTypeBuffer);
|
||||||
|
matrixStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,21 +3,40 @@ package de.ellpeck.prettypipes.blocks.pipe;
|
||||||
import de.ellpeck.prettypipes.PrettyPipes;
|
import de.ellpeck.prettypipes.PrettyPipes;
|
||||||
import de.ellpeck.prettypipes.Registry;
|
import de.ellpeck.prettypipes.Registry;
|
||||||
import de.ellpeck.prettypipes.items.UpgradeItem;
|
import de.ellpeck.prettypipes.items.UpgradeItem;
|
||||||
|
import de.ellpeck.prettypipes.network.NetworkEdge;
|
||||||
|
import de.ellpeck.prettypipes.network.PipeItem;
|
||||||
|
import de.ellpeck.prettypipes.network.PipeNetwork;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.inventory.container.Container;
|
import net.minecraft.inventory.container.Container;
|
||||||
import net.minecraft.inventory.container.INamedContainerProvider;
|
import net.minecraft.inventory.container.INamedContainerProvider;
|
||||||
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.tileentity.ITickableTileEntity;
|
||||||
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.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.TranslationTextComponent;
|
import net.minecraft.util.text.TranslationTextComponent;
|
||||||
|
import net.minecraftforge.common.util.Constants;
|
||||||
|
import net.minecraftforge.items.CapabilityItemHandler;
|
||||||
|
import net.minecraftforge.items.IItemHandler;
|
||||||
|
import net.minecraftforge.items.ItemHandlerHelper;
|
||||||
import net.minecraftforge.items.ItemStackHandler;
|
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.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class PipeTileEntity extends TileEntity implements INamedContainerProvider {
|
public class PipeTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
|
||||||
|
|
||||||
public final ItemStackHandler upgrades = new ItemStackHandler(3) {
|
public final ItemStackHandler upgrades = new ItemStackHandler(3) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,6 +44,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
return stack.getItem() instanceof UpgradeItem;
|
return stack.getItem() instanceof UpgradeItem;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
public final List<PipeItem> items = new ArrayList<>();
|
||||||
|
|
||||||
public PipeTileEntity() {
|
public PipeTileEntity() {
|
||||||
super(Registry.pipeTileEntity);
|
super(Registry.pipeTileEntity);
|
||||||
|
@ -44,12 +64,70 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public CompoundNBT write(CompoundNBT compound) {
|
||||||
compound.put("upgrades", this.upgrades.serializeNBT());
|
compound.put("upgrades", this.upgrades.serializeNBT());
|
||||||
|
ListNBT list = new ListNBT();
|
||||||
|
for (PipeItem item : this.items)
|
||||||
|
list.add(item.serializeNBT());
|
||||||
|
compound.put("items", list);
|
||||||
return super.write(compound);
|
return super.write(compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
public void read(CompoundNBT compound) {
|
||||||
this.upgrades.deserializeNBT(compound.getCompound("upgrades"));
|
this.upgrades.deserializeNBT(compound.getCompound("upgrades"));
|
||||||
|
this.items.clear();
|
||||||
|
ListNBT list = compound.getList("items", Constants.NBT.TAG_COMPOUND);
|
||||||
|
for (int i = 0; i < list.size(); i++)
|
||||||
|
this.items.add(new PipeItem(list.getCompound(i)));
|
||||||
super.read(compound);
|
super.read(compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
for (int i = this.items.size() - 1; i >= 0; i--)
|
||||||
|
this.items.get(i).updateInPipe(this);
|
||||||
|
|
||||||
|
// TODO make this extraction module stuff proper
|
||||||
|
PipeNetwork network = PipeNetwork.get(this.world);
|
||||||
|
for (int i = 0; i < this.upgrades.getSlots(); i++) {
|
||||||
|
if (this.upgrades.getStackInSlot(i).getItem() != Registry.extractionUpgradeItem)
|
||||||
|
continue;
|
||||||
|
BlockState state = this.getBlockState();
|
||||||
|
for (Direction dir : Direction.values()) {
|
||||||
|
if (!state.get(PipeBlock.DIRECTIONS.get(dir)).isConnected())
|
||||||
|
continue;
|
||||||
|
IItemHandler handler = this.getItemHandler(dir);
|
||||||
|
if (handler != null) {
|
||||||
|
for (int j = 0; j < handler.getSlots(); j++) {
|
||||||
|
ItemStack stack = handler.extractItem(j, 64, true);
|
||||||
|
if (!stack.isEmpty() && network.tryInsertItem(this.pos, this.pos.offset(dir), stack)) {
|
||||||
|
handler.extractItem(j, 64, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getAvailableDestination(ItemStack stack) {
|
||||||
|
for (Direction dir : Direction.values()) {
|
||||||
|
IItemHandler handler = this.getItemHandler(dir);
|
||||||
|
if (handler == null)
|
||||||
|
continue;
|
||||||
|
if (ItemHandlerHelper.insertItem(handler, stack, true).isEmpty())
|
||||||
|
return this.pos.offset(dir);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IItemHandler getItemHandler(Direction dir) {
|
||||||
|
BlockState state = this.getBlockState();
|
||||||
|
if (!state.get(PipeBlock.DIRECTIONS.get(dir)).isConnected())
|
||||||
|
return null;
|
||||||
|
TileEntity tile = this.world.getTileEntity(this.pos.offset(dir));
|
||||||
|
if (tile == null)
|
||||||
|
return null;
|
||||||
|
return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,20 +19,22 @@ import java.util.Map;
|
||||||
|
|
||||||
public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable<CompoundNBT> {
|
public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable<CompoundNBT> {
|
||||||
|
|
||||||
public final World world;
|
|
||||||
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<>();
|
private final Map<Integer, PipeTileEntity> tileCache = new HashMap<>();
|
||||||
|
|
||||||
public NetworkEdge(World world) {
|
public NetworkEdge(){
|
||||||
this.world = world;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PipeTileEntity getPipe(int index) {
|
public NetworkEdge(CompoundNBT nbt){
|
||||||
|
this.deserializeNBT(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PipeTileEntity getPipe(World world, int index) {
|
||||||
PipeTileEntity tile = this.tileCache.get(index);
|
PipeTileEntity tile = this.tileCache.get(index);
|
||||||
if (tile == null || tile.isRemoved()) {
|
if (tile == null || tile.isRemoved()) {
|
||||||
tile = Utility.getTileEntity(PipeTileEntity.class, this.world, this.pipes.get(index));
|
tile = Utility.getTileEntity(PipeTileEntity.class, world, this.pipes.get(index));
|
||||||
this.tileCache.put(index, tile);
|
this.tileCache.put(index, tile);
|
||||||
}
|
}
|
||||||
return tile;
|
return tile;
|
||||||
|
|
157
src/main/java/de/ellpeck/prettypipes/network/PipeItem.java
Normal file
157
src/main/java/de/ellpeck/prettypipes/network/PipeItem.java
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package de.ellpeck.prettypipes.network;
|
||||||
|
|
||||||
|
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.ListNBT;
|
||||||
|
import net.minecraft.nbt.NBTUtil;
|
||||||
|
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 org.jgrapht.GraphPath;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PipeItem implements INBTSerializable<CompoundNBT> {
|
||||||
|
|
||||||
|
public static final int PIPE_TIME = 40;
|
||||||
|
|
||||||
|
public ItemStack stack;
|
||||||
|
public float x;
|
||||||
|
public float y;
|
||||||
|
public float z;
|
||||||
|
|
||||||
|
private final List<NetworkEdge> pathEdges;
|
||||||
|
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) {
|
||||||
|
this.stack = stack;
|
||||||
|
this.startPipe = startPipe;
|
||||||
|
this.destPipe = destPipe;
|
||||||
|
this.destInventory = destInventory;
|
||||||
|
this.pathEdges = path.getEdgeList();
|
||||||
|
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.deserializeNBT(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateInPipe(PipeTileEntity currPipe) {
|
||||||
|
this.pipeTimer++;
|
||||||
|
BlockPos goalPos;
|
||||||
|
if (this.pipeTimer >= PIPE_TIME) {
|
||||||
|
// we're done with the current pipe, so switch to the next one
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
next.items.add(this);
|
||||||
|
this.pipeTimer = 0;
|
||||||
|
goalPos = next.getPos();
|
||||||
|
}
|
||||||
|
} else if (this.pipeTimer >= PIPE_TIME / 2) {
|
||||||
|
// 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;
|
||||||
|
} else {
|
||||||
|
goalPos = next.getPos();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we're at the start of the pipe, so just move towards its center
|
||||||
|
goalPos = currPipe.getPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
this.x += dist.x * speed;
|
||||||
|
this.y += dist.y * speed;
|
||||||
|
this.z += dist.z * speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void store(PipeTileEntity currPipe) {
|
||||||
|
if (currPipe.getWorld().isRemote)
|
||||||
|
return;
|
||||||
|
// TODO store in destination
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundNBT serializeNBT() {
|
||||||
|
CompoundNBT nbt = new CompoundNBT();
|
||||||
|
nbt.put("stack", this.stack.serializeNBT());
|
||||||
|
nbt.put("start_pipe", NBTUtil.writeBlockPos(this.startPipe));
|
||||||
|
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());
|
||||||
|
nbt.put("path", list);
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT(CompoundNBT nbt) {
|
||||||
|
this.stack = ItemStack.read(nbt.getCompound("stack"));
|
||||||
|
this.startPipe = NBTUtil.readBlockPos(nbt.getCompound("start_pipe"));
|
||||||
|
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();
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,15 @@ import de.ellpeck.prettypipes.Registry;
|
||||||
import de.ellpeck.prettypipes.Utility;
|
import de.ellpeck.prettypipes.Utility;
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeBlock;
|
import de.ellpeck.prettypipes.blocks.pipe.PipeBlock;
|
||||||
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
|
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.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
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.Direction;
|
||||||
import net.minecraft.util.Tuple;
|
import net.minecraft.util.Tuple;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -18,18 +22,25 @@ import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||||
import net.minecraftforge.common.util.Constants;
|
import net.minecraftforge.common.util.Constants;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
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.alg.shortestpath.DijkstraShortestPath;
|
||||||
import org.jgrapht.graph.SimpleWeightedGraph;
|
import org.jgrapht.graph.SimpleWeightedGraph;
|
||||||
|
import org.jgrapht.traverse.ClosestFirstIterator;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
|
public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
|
||||||
|
|
||||||
public final SimpleWeightedGraph<BlockPos, NetworkEdge> graph = new SimpleWeightedGraph<>(NetworkEdge.class);
|
public final SimpleWeightedGraph<BlockPos, NetworkEdge> graph = new SimpleWeightedGraph<>(NetworkEdge.class);
|
||||||
private final DijkstraShortestPath<BlockPos, NetworkEdge> dijkstra = new DijkstraShortestPath<>(this.graph);
|
private final DijkstraShortestPath<BlockPos, NetworkEdge> dijkstra = new DijkstraShortestPath<>(this.graph);
|
||||||
|
private final Map<BlockPos, PipeTileEntity> tileCache = new HashMap<>();
|
||||||
private final World world;
|
private final World world;
|
||||||
|
|
||||||
public PipeNetwork(World world) {
|
public PipeNetwork(World world) {
|
||||||
|
@ -63,34 +74,69 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
|
||||||
for (int i = 0; i < nodes.size(); i++)
|
for (int i = 0; i < nodes.size(); i++)
|
||||||
this.graph.addVertex(NBTUtil.readBlockPos(nodes.getCompound(i)));
|
this.graph.addVertex(NBTUtil.readBlockPos(nodes.getCompound(i)));
|
||||||
ListNBT edges = nbt.getList("edges", Constants.NBT.TAG_COMPOUND);
|
ListNBT edges = nbt.getList("edges", Constants.NBT.TAG_COMPOUND);
|
||||||
for (int i = 0; i < edges.size(); i++) {
|
for (int i = 0; i < edges.size(); i++)
|
||||||
NetworkEdge edge = new NetworkEdge(this.world);
|
this.addEdge(new NetworkEdge(edges.getCompound(i)));
|
||||||
edge.deserializeNBT(edges.getCompound(i));
|
|
||||||
this.addEdge(edge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addNode(BlockPos pos, BlockState state) {
|
public void addNode(BlockPos pos, BlockState state) {
|
||||||
if (!this.graph.containsVertex(pos)) {
|
if (!this.isNode(pos)) {
|
||||||
this.graph.addVertex(pos);
|
this.graph.addVertex(pos);
|
||||||
this.refreshNode(pos, state);
|
this.refreshNode(pos, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeNode(BlockPos pos) {
|
public void removeNode(BlockPos pos) {
|
||||||
if (this.graph.containsVertex(pos))
|
if (this.isNode(pos))
|
||||||
this.graph.removeVertex(pos);
|
this.graph.removeVertex(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNode(BlockPos pos) {
|
||||||
|
return this.graph.containsVertex(pos);
|
||||||
|
}
|
||||||
|
|
||||||
public void onPipeChanged(BlockPos pos, BlockState state) {
|
public void onPipeChanged(BlockPos pos, BlockState state) {
|
||||||
List<NetworkEdge> neighbors = this.createAllEdges(pos, state, true);
|
List<NetworkEdge> neighbors = this.createAllEdges(pos, state, true);
|
||||||
// if we only have one neighbor, then there can't be any new connections
|
// if we only have one neighbor, then there can't be any new connections
|
||||||
if (neighbors.size() <= 1 && !this.graph.containsVertex(pos))
|
if (neighbors.size() <= 1 && !this.isNode(pos))
|
||||||
return;
|
return;
|
||||||
for (NetworkEdge edge : neighbors)
|
for (NetworkEdge edge : neighbors)
|
||||||
this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe));
|
this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean tryInsertItem(BlockPos startPipePos, BlockPos originInv, ItemStack stack) {
|
||||||
|
if (!this.isNode(startPipePos))
|
||||||
|
return false;
|
||||||
|
PipeTileEntity startPipe = this.getPipe(startPipePos);
|
||||||
|
if (startPipe == null)
|
||||||
|
return false;
|
||||||
|
ClosestFirstIterator<BlockPos, NetworkEdge> it = new ClosestFirstIterator<>(this.graph, startPipePos);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
PipeTileEntity pipe = this.getPipe(it.next());
|
||||||
|
// don't try to insert into yourself, duh
|
||||||
|
if (pipe == startPipe)
|
||||||
|
continue;
|
||||||
|
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));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PipeTileEntity getPipe(BlockPos pos) {
|
||||||
|
PipeTileEntity tile = this.tileCache.get(pos);
|
||||||
|
if (tile == null || tile.isRemoved()) {
|
||||||
|
tile = Utility.getTileEntity(PipeTileEntity.class, this.world, pos);
|
||||||
|
this.tileCache.put(pos, tile);
|
||||||
|
}
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshNode(BlockPos pos, BlockState state) {
|
private void refreshNode(BlockPos pos, BlockState state) {
|
||||||
this.graph.removeAllEdges(new ArrayList<>(this.graph.edgesOf(pos)));
|
this.graph.removeAllEdges(new ArrayList<>(this.graph.edgesOf(pos)));
|
||||||
for (NetworkEdge edge : this.createAllEdges(pos, state, false))
|
for (NetworkEdge edge : this.createAllEdges(pos, state, false))
|
||||||
|
@ -119,7 +165,7 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
|
||||||
BlockState currState = this.world.getBlockState(currPos);
|
BlockState currState = this.world.getBlockState(currPos);
|
||||||
if (!(currState.getBlock() instanceof PipeBlock))
|
if (!(currState.getBlock() instanceof PipeBlock))
|
||||||
return null;
|
return null;
|
||||||
NetworkEdge edge = new NetworkEdge(this.world);
|
NetworkEdge edge = new NetworkEdge();
|
||||||
edge.startPipe = pos;
|
edge.startPipe = pos;
|
||||||
edge.pipes.add(pos);
|
edge.pipes.add(pos);
|
||||||
edge.pipes.add(currPos);
|
edge.pipes.add(currPos);
|
||||||
|
@ -127,7 +173,7 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
|
||||||
while (true) {
|
while (true) {
|
||||||
// if we found a vertex, we can stop since that's the next node
|
// if we found a vertex, we can stop since that's the next node
|
||||||
// we do this here since the first offset pipe also needs to check this
|
// we do this here since the first offset pipe also needs to check this
|
||||||
if (this.graph.containsVertex(currPos)) {
|
if (this.isNode(currPos)) {
|
||||||
edge.endPipe = edge.pipes.get(edge.pipes.size() - 1);
|
edge.endPipe = edge.pipes.get(edge.pipes.size() - 1);
|
||||||
return edge;
|
return edge;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package de.ellpeck.prettypipes.packets;
|
||||||
|
|
||||||
|
import de.ellpeck.prettypipes.PrettyPipes;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.fml.network.PacketDistributor;
|
||||||
|
import net.minecraftforge.fml.network.simple.SimpleChannel;
|
||||||
|
|
||||||
|
public final class PacketHandler {
|
||||||
|
|
||||||
|
private static final String VERSION = "1";
|
||||||
|
private static SimpleChannel network;
|
||||||
|
|
||||||
|
public static void setup() {
|
||||||
|
network = NetworkRegistry.newSimpleChannel(new ResourceLocation(PrettyPipes.ID, "network"), () -> VERSION, VERSION::equals, VERSION::equals);
|
||||||
|
network.registerMessage(0, PacketItemEnterPipe.class, PacketItemEnterPipe::toBytes, PacketItemEnterPipe::fromBytes, PacketItemEnterPipe::onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendToAllLoaded(World world, BlockPos pos, Object message) {
|
||||||
|
network.send(PacketDistributor.TRACKING_CHUNK.with(() -> world.getChunkAt(pos)), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendToAllAround(IWorld world, BlockPos pos, int range, Object message) {
|
||||||
|
network.send(PacketDistributor.NEAR.with(() -> new PacketDistributor.TargetPoint(pos.getX(), pos.getY(), pos.getZ(), range, world.getDimension().getType())), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendTo(PlayerEntity player, Object message) {
|
||||||
|
network.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package de.ellpeck.prettypipes.packets;
|
||||||
|
|
||||||
|
import de.ellpeck.prettypipes.Utility;
|
||||||
|
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
|
||||||
|
import de.ellpeck.prettypipes.network.PipeItem;
|
||||||
|
import de.ellpeck.prettypipes.network.PipeNetwork;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraftforge.fml.network.NetworkEvent;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class PacketItemEnterPipe {
|
||||||
|
|
||||||
|
private BlockPos tilePos;
|
||||||
|
private CompoundNBT item;
|
||||||
|
|
||||||
|
public PacketItemEnterPipe(BlockPos tilePos, PipeItem item) {
|
||||||
|
this.tilePos = tilePos;
|
||||||
|
this.item = item.serializeNBT();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PacketItemEnterPipe() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PacketItemEnterPipe fromBytes(PacketBuffer buf) {
|
||||||
|
PacketItemEnterPipe client = new PacketItemEnterPipe();
|
||||||
|
client.tilePos = buf.readBlockPos();
|
||||||
|
client.item = buf.readCompoundTag();
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void toBytes(PacketItemEnterPipe packet, PacketBuffer buf) {
|
||||||
|
buf.writeBlockPos(packet.tilePos);
|
||||||
|
buf.writeCompoundTag(packet.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Convert2Lambda")
|
||||||
|
public static void onMessage(PacketItemEnterPipe message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
|
ctx.get().enqueueWork(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
if (mc.world == null)
|
||||||
|
return;
|
||||||
|
PipeItem item = new PipeItem(message.item);
|
||||||
|
PipeTileEntity pipe = Utility.getTileEntity(PipeTileEntity.class, mc.world, message.tilePos);
|
||||||
|
if (pipe != null)
|
||||||
|
pipe.items.add(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.get().setPacketHandled(true);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue