got network connections fully working!

This commit is contained in:
Ellpeck 2020-04-14 14:10:58 +02:00
parent bf60a40457
commit 87de8e353d
4 changed files with 89 additions and 56 deletions

View file

@ -5,6 +5,7 @@ import de.ellpeck.prettypipes.Utility;
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;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.InventoryHelper; import net.minecraft.inventory.InventoryHelper;
@ -95,6 +96,11 @@ public class PipeBlock extends ContainerBlock {
return this.createState(context.getWorld(), context.getPos(), this.getDefaultState()); return this.createState(context.getWorld(), context.getPos(), this.getDefaultState());
} }
@Override
public void onBlockPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
onStateChanged(worldIn, pos, state);
}
@Override @Override
public boolean isNormalCube(BlockState state, IBlockReader worldIn, BlockPos pos) { public boolean isNormalCube(BlockState state, IBlockReader worldIn, BlockPos pos) {
return false; return false;

View file

@ -2,18 +2,11 @@ package de.ellpeck.prettypipes.events;
import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.network.PipeNetwork;
import net.minecraft.particles.ParticleType;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.particles.RedstoneParticleData;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import org.jgrapht.graph.DefaultWeightedEdge;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public final class Events { public final class Events {
@ -22,22 +15,4 @@ public final class Events {
public static void onWorldCaps(AttachCapabilitiesEvent<World> event) { public static void onWorldCaps(AttachCapabilitiesEvent<World> event) {
event.addCapability(new ResourceLocation(PrettyPipes.ID, "network"), new PipeNetwork(event.getObject())); event.addCapability(new ResourceLocation(PrettyPipes.ID, "network"), new PipeNetwork(event.getObject()));
} }
@SubscribeEvent
public static void onWorldTick(TickEvent.WorldTickEvent event) {
if (event.phase != TickEvent.Phase.END)
return;
if (event.world.getGameTime() % 5 != 0)
return;
PipeNetwork network = PipeNetwork.get(event.world);
for (DefaultWeightedEdge edge : network.graph.edgeSet()) {
BlockPos start = network.graph.getEdgeSource(edge);
BlockPos end = network.graph.getEdgeTarget(edge);
RedstoneParticleData data = new RedstoneParticleData(((start.getX() * 181923 + end.getX()) % 255) / 255F, ((start.getY() * 128391 + end.getY()) % 255) / 255F, ((start.getZ() * 123891 + end.getZ()) % 255) / 255F, 1);
((ServerWorld) event.world).spawnParticle(data, start.getX() + 0.5F, start.getY() + 0.5F, start.getZ() + 0.5F, 1, 0, 0, 0, 0);
((ServerWorld) event.world).spawnParticle(data, end.getX() + 0.5F, end.getY() + 0.5F, end.getZ() + 0.5F, 1, 0, 0, 0, 0);
}
}
} }

View file

@ -0,0 +1,14 @@
package de.ellpeck.prettypipes.network;
import net.minecraft.tileentity.TileEntity;
import org.jgrapht.graph.DefaultWeightedEdge;
import java.util.ArrayList;
import java.util.List;
public class NetworkEdge extends DefaultWeightedEdge {
public TileEntity startPipe;
public List<TileEntity> pipes = new ArrayList<>();
public TileEntity endPipe;
}

View file

@ -2,7 +2,9 @@ package de.ellpeck.prettypipes.network;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Registry;
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 net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
@ -31,8 +33,8 @@ import java.util.Set;
public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> { public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
public final SimpleWeightedGraph<BlockPos, DefaultWeightedEdge> graph = new SimpleWeightedGraph<>(DefaultWeightedEdge.class); public final SimpleWeightedGraph<BlockPos, NetworkEdge> graph = new SimpleWeightedGraph<>(NetworkEdge.class);
private final DijkstraShortestPath<BlockPos, DefaultWeightedEdge> dijkstra = new DijkstraShortestPath<>(this.graph); private final DijkstraShortestPath<BlockPos, NetworkEdge> dijkstra = new DijkstraShortestPath<>(this.graph);
private final World world; private final World world;
public PipeNetwork(World world) { public PipeNetwork(World world) {
@ -68,48 +70,84 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT> {
} }
public void onPipeChanged(BlockPos pos, BlockState state) { public void onPipeChanged(BlockPos pos, BlockState state) {
Set<Pair<BlockPos, Integer>> neighbors = this.findConnectedNodesInPipe(pos, state); 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.graph.containsVertex(pos))
return; return;
for (Pair<BlockPos, Integer> node : neighbors) for (NetworkEdge edge : neighbors) {
this.refreshNode(node.getLeft(), this.world.getBlockState(node.getLeft())); BlockPos end = edge.endPipe.getPos();
System.out.println(this.graph); this.refreshNode(end, this.world.getBlockState(end));
}
System.out.println(this.graph.toString());
} }
private void refreshNode(BlockPos pos, BlockState state) { private void refreshNode(BlockPos pos, BlockState state) {
Set<DefaultWeightedEdge> edges = this.graph.edgesOf(pos); Set<NetworkEdge> edges = this.graph.edgesOf(pos);
this.graph.removeAllEdges(new ArrayList<>(edges)); this.graph.removeAllEdges(new ArrayList<>(edges));
for (Pair<BlockPos, Integer> node : this.findConnectedNodesInPipe(pos, state)) { for (NetworkEdge edge : this.createAllEdges(pos, state, false)) {
DefaultWeightedEdge edge = this.graph.addEdge(pos, node.getLeft()); this.graph.addEdge(edge.startPipe.getPos(), edge.endPipe.getPos(), edge);
this.graph.setEdgeWeight(edge, node.getRight()); this.graph.setEdgeWeight(edge, edge.pipes.size());
} }
} }
private Set<Pair<BlockPos, Integer>> findConnectedNodesInPipe(BlockPos pos, BlockState state) { private List<NetworkEdge> createAllEdges(BlockPos pos, BlockState state, boolean allAround) {
Set<Pair<BlockPos, Integer>> set = new HashSet<>(); List<NetworkEdge> edges = new ArrayList<>();
this.findConnectedNodesInPipe(pos, state, set, Sets.newHashSet(pos), 0);
return set;
}
private void findConnectedNodesInPipe(BlockPos pos, BlockState state, Set<Pair<BlockPos, Integer>> nodes, Set<BlockPos> seen, int iterations) {
if (!(state.getBlock() instanceof PipeBlock))
return;
for (Direction dir : Direction.values()) { for (Direction dir : Direction.values()) {
if (!state.get(PipeBlock.DIRECTIONS.get(dir)).isConnected()) NetworkEdge edge = this.createEdge(pos, state, dir, allAround);
if (edge != null)
edges.add(edge);
}
return edges;
}
private NetworkEdge createEdge(BlockPos pos, BlockState state, Direction dir, boolean allAround) {
if (!allAround && !state.get(PipeBlock.DIRECTIONS.get(dir)).isConnected())
return null;
BlockPos currPos = pos.offset(dir);
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));
Set<BlockPos> 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
if (this.graph.containsVertex(currPos)) {
edge.endPipe = edge.pipes.get(edge.pipes.size() - 1);
return edge;
}
boolean found = false;
for (Direction nextDir : Direction.values()) {
if (!currState.get(PipeBlock.DIRECTIONS.get(nextDir)).isConnected())
continue; continue;
BlockPos offset = pos.offset(dir); BlockPos offset = currPos.offset(nextDir);
if (seen.contains(offset)) if (seen.contains(offset))
continue; continue;
seen.add(offset); seen.add(offset);
if (this.graph.containsVertex(offset)) { BlockState offState = this.world.getBlockState(offset);
nodes.add(Pair.of(offset, iterations)); if (!(offState.getBlock() instanceof PipeBlock))
continue;
edge.pipes.add(Utility.getTileEntity(PipeTileEntity.class, this.world, offset));
currPos = offset;
currState = offState;
found = true;
break; break;
} else {
this.findConnectedNodesInPipe(offset, this.world.getBlockState(offset), nodes, seen, iterations + 1);
} }
if (!found)
break;
} }
return null;
} }
public static PipeNetwork get(World world) { public static PipeNetwork get(World world) {