diff --git a/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java b/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java index a301c60..bffebba 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java +++ b/src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java @@ -1,14 +1,62 @@ package de.ellpeck.prettypipes.network; +import de.ellpeck.prettypipes.Utility; +import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.INBTSerializable; import org.jgrapht.graph.DefaultWeightedEdge; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -public class NetworkEdge extends DefaultWeightedEdge { +public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable { - public TileEntity startPipe; - public List pipes = new ArrayList<>(); - public TileEntity endPipe; + public final World world; + public BlockPos startPipe; + public BlockPos endPipe; + public final List pipes = new ArrayList<>(); + private final Map tileCache = new HashMap<>(); + + public NetworkEdge(World world) { + this.world = world; + } + + public PipeTileEntity getPipe(int index) { + PipeTileEntity tile = this.tileCache.get(index); + if (tile == null || tile.isRemoved()) { + tile = Utility.getTileEntity(PipeTileEntity.class, this.world, this.pipes.get(index)); + this.tileCache.put(index, tile); + } + return tile; + } + + @Override + public CompoundNBT serializeNBT() { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("start", NBTUtil.writeBlockPos(this.startPipe)); + nbt.put("end", NBTUtil.writeBlockPos(this.endPipe)); + ListNBT list = new ListNBT(); + for (BlockPos pos : this.pipes) + list.add(NBTUtil.writeBlockPos(pos)); + nbt.put("pipes", list); + return nbt; + } + + @Override + public void deserializeNBT(CompoundNBT nbt) { + this.startPipe = NBTUtil.readBlockPos(nbt.getCompound("start")); + this.endPipe = NBTUtil.readBlockPos(nbt.getCompound("end")); + this.pipes.clear(); + ListNBT list = nbt.getList("pipes", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < list.size(); i++) + this.pipes.add(NBTUtil.readBlockPos(list.getCompound(i))); + } } diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index 2d19816..90d6853 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -8,28 +8,23 @@ import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; 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; import net.minecraftforge.common.capabilities.ICapabilitySerializable; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.LazyOptional; -import org.apache.commons.lang3.tuple.Pair; -import org.jgrapht.Graphs; import org.jgrapht.alg.shortestpath.DijkstraShortestPath; -import org.jgrapht.graph.DefaultEdge; -import org.jgrapht.graph.DefaultWeightedEdge; -import org.jgrapht.graph.SimpleGraph; import org.jgrapht.graph.SimpleWeightedGraph; -import org.jheaps.tree.FibonacciHeap; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class PipeNetwork implements ICapabilitySerializable { @@ -49,12 +44,30 @@ public class PipeNetwork implements ICapabilitySerializable { @Override public CompoundNBT serializeNBT() { - return new CompoundNBT(); + CompoundNBT nbt = new CompoundNBT(); + ListNBT nodes = new ListNBT(); + for (BlockPos node : this.graph.vertexSet()) + nodes.add(NBTUtil.writeBlockPos(node)); + nbt.put("nodes", nodes); + ListNBT edges = new ListNBT(); + for (NetworkEdge edge : this.graph.edgeSet()) + edges.add(edge.serializeNBT()); + nbt.put("edges", edges); + return nbt; } @Override public void deserializeNBT(CompoundNBT nbt) { - + this.graph.removeAllVertices(new ArrayList<>(this.graph.vertexSet())); + ListNBT nodes = nbt.getList("nodes", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < nodes.size(); i++) + this.graph.addVertex(NBTUtil.readBlockPos(nodes.getCompound(i))); + ListNBT edges = nbt.getList("edges", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < edges.size(); i++) { + NetworkEdge edge = new NetworkEdge(this.world); + edge.deserializeNBT(edges.getCompound(i)); + this.addEdge(edge); + } } public void addNode(BlockPos pos, BlockState state) { @@ -74,21 +87,19 @@ public class PipeNetwork implements ICapabilitySerializable { // if we only have one neighbor, then there can't be any new connections if (neighbors.size() <= 1 && !this.graph.containsVertex(pos)) return; - for (NetworkEdge edge : neighbors) { - BlockPos end = edge.endPipe.getPos(); - this.refreshNode(end, this.world.getBlockState(end)); - } - System.out.println(this.graph.toString()); + for (NetworkEdge edge : neighbors) + this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe)); } private void refreshNode(BlockPos pos, BlockState state) { - Set edges = this.graph.edgesOf(pos); - this.graph.removeAllEdges(new ArrayList<>(edges)); + this.graph.removeAllEdges(new ArrayList<>(this.graph.edgesOf(pos))); + for (NetworkEdge edge : this.createAllEdges(pos, state, false)) + this.addEdge(edge); + } - for (NetworkEdge edge : this.createAllEdges(pos, state, false)) { - this.graph.addEdge(edge.startPipe.getPos(), edge.endPipe.getPos(), edge); - this.graph.setEdgeWeight(edge, edge.pipes.size()); - } + private void addEdge(NetworkEdge edge) { + this.graph.addEdge(edge.startPipe, edge.endPipe, edge); + this.graph.setEdgeWeight(edge, edge.pipes.size()); } private List createAllEdges(BlockPos pos, BlockState state, boolean allAround) { @@ -108,17 +119,11 @@ public class PipeNetwork implements ICapabilitySerializable { BlockState currState = this.world.getBlockState(currPos); if (!(currState.getBlock() instanceof PipeBlock)) return null; - NetworkEdge edge = new NetworkEdge(); - PipeTileEntity startPipe = Utility.getTileEntity(PipeTileEntity.class, this.world, pos); - if (startPipe != null) { - edge.startPipe = startPipe; - edge.pipes.add(startPipe); - } - edge.pipes.add(Utility.getTileEntity(PipeTileEntity.class, this.world, currPos)); + NetworkEdge edge = new NetworkEdge(this.world); + edge.startPipe = pos; + edge.pipes.add(pos); + edge.pipes.add(currPos); - Set seen = new HashSet<>(); - seen.add(pos); - seen.add(currPos); while (true) { // 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 @@ -132,13 +137,12 @@ public class PipeNetwork implements ICapabilitySerializable { if (!currState.get(PipeBlock.DIRECTIONS.get(nextDir)).isConnected()) continue; BlockPos offset = currPos.offset(nextDir); - if (seen.contains(offset)) - continue; - seen.add(offset); BlockState offState = this.world.getBlockState(offset); if (!(offState.getBlock() instanceof PipeBlock)) continue; - edge.pipes.add(Utility.getTileEntity(PipeTileEntity.class, this.world, offset)); + if (edge.pipes.contains(offset)) + continue; + edge.pipes.add(offset); currPos = offset; currState = offState; found = true;