Skip to content
This repository has been archived by the owner on Nov 18, 2023. It is now read-only.

Commit

Permalink
Better architecture for networks.
Browse files Browse the repository at this point in the history
  • Loading branch information
raoulvdberge committed Mar 30, 2020
1 parent 2137808 commit 72ba197
Show file tree
Hide file tree
Showing 30 changed files with 399 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.raoulvdberge.refinedpipes.network.pipe.fluid.FluidPipeType;
import com.raoulvdberge.refinedpipes.tile.FluidPipeTileEntity;
import com.raoulvdberge.refinedpipes.tile.PipeTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
Expand Down Expand Up @@ -39,18 +38,18 @@ public TileEntity createTileEntity(BlockState state, IBlockReader world) {
@Override
protected boolean hasConnection(IWorld world, BlockPos pos, Direction direction) {
TileEntity currentTile = world.getTileEntity(pos);
if (currentTile instanceof PipeTileEntity && ((PipeTileEntity) currentTile).hasAttachment(direction)) {
if (currentTile instanceof FluidPipeTileEntity && ((FluidPipeTileEntity) currentTile).hasAttachment(direction)) {
return false;
}

BlockState facingState = world.getBlockState(pos.offset(direction));
TileEntity facingTile = world.getTileEntity(pos.offset(direction));

if (facingTile instanceof PipeTileEntity && ((PipeTileEntity) facingTile).hasAttachment(direction.getOpposite())) {
if (facingTile instanceof FluidPipeTileEntity && ((FluidPipeTileEntity) facingTile).hasAttachment(direction.getOpposite())) {
return false;
}

return facingState.getBlock() instanceof PipeBlock;
return facingState.getBlock() instanceof FluidPipeBlock;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.raoulvdberge.refinedpipes.network.pipe.item.ItemPipeType;
import com.raoulvdberge.refinedpipes.tile.ItemPipeTileEntity;
import com.raoulvdberge.refinedpipes.tile.PipeTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
Expand Down Expand Up @@ -39,18 +38,18 @@ public TileEntity createTileEntity(BlockState state, IBlockReader world) {
@Override
protected boolean hasConnection(IWorld world, BlockPos pos, Direction direction) {
TileEntity currentTile = world.getTileEntity(pos);
if (currentTile instanceof PipeTileEntity && ((PipeTileEntity) currentTile).hasAttachment(direction)) {
if (currentTile instanceof ItemPipeTileEntity && ((ItemPipeTileEntity) currentTile).hasAttachment(direction)) {
return false;
}

BlockState facingState = world.getBlockState(pos.offset(direction));
TileEntity facingTile = world.getTileEntity(pos.offset(direction));

if (facingTile instanceof PipeTileEntity && ((PipeTileEntity) facingTile).hasAttachment(direction.getOpposite())) {
if (facingTile instanceof ItemPipeTileEntity && ((ItemPipeTileEntity) facingTile).hasAttachment(direction.getOpposite())) {
return false;
}

return facingState.getBlock() instanceof PipeBlock;
return facingState.getBlock() instanceof ItemPipeBlock;
}

@Override
Expand Down
92 changes: 12 additions & 80 deletions src/main/java/com/raoulvdberge/refinedpipes/network/Network.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
package com.raoulvdberge.refinedpipes.network;

import com.raoulvdberge.refinedpipes.network.graph.NetworkGraph;
import com.raoulvdberge.refinedpipes.network.graph.scanner.NetworkGraphScannerResult;
import com.raoulvdberge.refinedpipes.network.pipe.fluid.FluidDestination;
import com.raoulvdberge.refinedpipes.util.StringUtil;
import com.raoulvdberge.refinedpipes.network.graph.NetworkGraphScannerResult;
import com.raoulvdberge.refinedpipes.network.pipe.Pipe;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Objects;
import java.util.Random;

public class Network {
private static final Logger LOGGER = LogManager.getLogger(Network.class);

private final NetworkGraph graph = new NetworkGraph(this);
public abstract class Network {
protected final NetworkGraph graph = new NetworkGraph(this);
private final String id;
private BlockPos originPos;
private boolean didDoInitialScan;
private FluidTank fluidTank = new FluidTank(FluidAttributes.BUCKET_VOLUME);

public Network(BlockPos originPos) {
this(originPos, StringUtil.randomString(new Random(), 8));
}

public Network(BlockPos originPos, String id) {
this.id = id;
Expand All @@ -46,85 +29,34 @@ public String getId() {
return id;
}

public NetworkGraphScannerResult scanGraph(World originWorld, BlockPos originPos) {
return graph.scan(originWorld, originPos);
}

public FluidTank getFluidTank() {
return fluidTank;
public NetworkGraphScannerResult scanGraph(World world, BlockPos pos) {
return graph.scan(world, pos);
}

public CompoundNBT writeToNbt(CompoundNBT tag) {
tag.putString("id", id);
tag.putLong("origin", originPos.toLong());
tag.put("tank", fluidTank.writeToNBT(new CompoundNBT()));

return tag;
}

public static Network fromNbt(CompoundNBT tag) {
Network network = new Network(BlockPos.fromLong(tag.getLong("origin")), tag.getString("id"));

if (tag.contains("tank")) {
network.fluidTank.readFromNBT(tag.getCompound("tank"));
}

LOGGER.debug("Deserialized network {}", network.id);

return network;
}

public void update(World world) {
if (!didDoInitialScan) {
didDoInitialScan = true;

scanGraph(world, originPos);
}

if (!fluidTank.getFluid().isEmpty() && !graph.getFluidDestinations().isEmpty()) {
int toDistribute = (int) Math.floor((float) getThroughput() / (float) graph.getFluidDestinations().size());

for (FluidDestination fluidDestination : graph.getFluidDestinations()) {
TileEntity tile = fluidDestination.getConnectedPipe().getWorld().getTileEntity(fluidDestination.getReceiver());
if (tile == null) {
continue;
}

IFluidHandler handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, fluidDestination.getIncomingDirection().getOpposite()).orElse(null);
if (handler == null) {
continue;
}

FluidStack drained = fluidTank.drain(toDistribute, IFluidHandler.FluidAction.EXECUTE);
if (drained.isEmpty()) {
continue;
}

int filled = handler.fill(drained, IFluidHandler.FluidAction.EXECUTE);

int remainder = drained.getAmount() - filled;
if (remainder > 0) {
drained = drained.copy();
drained.setAmount(remainder);

fluidTank.fill(drained, IFluidHandler.FluidAction.EXECUTE);
}
}
}

graph.getPipes().forEach(p -> p.update(world));
}

private int getThroughput() {
int viscosity = fluidTank.getFluid().getFluid().getAttributes().getViscosity(fluidTank.getFluid());
viscosity = Math.max(100, viscosity);

return MathHelper.clamp(120000 / viscosity, 80, 600);
public Pipe getPipe(BlockPos pos) {
return graph.getPipes().stream().filter(p -> p.getPos().equals(pos)).findFirst().orElse(null);
}

public NetworkGraph getGraph() {
return graph;
}
public abstract void onMergedWith(Network mainNetwork);

public abstract ResourceLocation getType();

@Override
public boolean equals(Object o) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.raoulvdberge.refinedpipes.network;

import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.BlockPos;

public interface NetworkFactory {
Network create(BlockPos pos);

Network create(CompoundNBT tag);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.raoulvdberge.refinedpipes.network;

import com.raoulvdberge.refinedpipes.RefinedPipes;
import com.raoulvdberge.refinedpipes.network.graph.scanner.NetworkGraphScannerResult;
import com.raoulvdberge.refinedpipes.network.graph.NetworkGraphScannerResult;
import com.raoulvdberge.refinedpipes.network.pipe.Pipe;
import com.raoulvdberge.refinedpipes.network.pipe.PipeFactory;
import com.raoulvdberge.refinedpipes.network.pipe.PipeRegistry;
Expand All @@ -16,7 +16,6 @@
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.capability.IFluidHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand Down Expand Up @@ -71,8 +70,8 @@ public void removeNetwork(String id) {
markDirty();
}

private void formNetworkAt(World world, BlockPos pos) {
Network network = new Network(pos);
private void formNetworkAt(World world, BlockPos pos, ResourceLocation type) {
Network network = NetworkRegistry.INSTANCE.getFactory(type).create(pos);

addNetwork(network);

Expand Down Expand Up @@ -102,9 +101,13 @@ private void mergeNetworksIntoOne(Set<Pipe> candidates, World world, BlockPos po
// Remove all the other networks.
Network otherNetwork = networks.next();

mainNetwork.getFluidTank().fill(otherNetwork.getFluidTank().getFluid(), IFluidHandler.FluidAction.EXECUTE);
boolean canMerge = mainNetwork.getType().equals(otherNetwork.getType());

removeNetwork(otherNetwork.getId());
if (canMerge) {
otherNetwork.onMergedWith(mainNetwork);

removeNetwork(otherNetwork.getId());
}
}

mainNetwork.scanGraph(world, pos);
Expand All @@ -121,10 +124,10 @@ public void addPipe(Pipe pipe) {

markDirty();

Set<Pipe> adjacentPipes = findAdjacentPipes(pipe.getPos());
Set<Pipe> adjacentPipes = findAdjacentPipes(pipe.getPos(), pipe.getNetworkType());

if (adjacentPipes.isEmpty()) {
formNetworkAt(pipe.getWorld(), pipe.getPos());
formNetworkAt(pipe.getWorld(), pipe.getPos(), pipe.getNetworkType());
} else {
mergeNetworksIntoOne(adjacentPipes, pipe.getWorld(), pipe.getPos());
}
Expand All @@ -151,7 +154,7 @@ public void removePipe(BlockPos pos) {

private void splitNetworks(Pipe originPipe) {
// Sanity checks
for (Pipe adjacent : findAdjacentPipes(originPipe.getPos())) {
for (Pipe adjacent : findAdjacentPipes(originPipe.getPos(), originPipe.getNetworkType())) {
if (adjacent.getNetwork() == null) {
throw new RuntimeException("Adjacent pipe has no network");
}
Expand All @@ -161,9 +164,9 @@ private void splitNetworks(Pipe originPipe) {
}
}

// We can assume all adjacent pipes shared the same network with the removed pipe.
// We can assume all adjacent pipes (with the same network type) share the same network with the removed pipe.
// That means it doesn't matter which pipe network we use for splitting, we'll take the first found one.
Pipe otherPipeInNetwork = findFirstAdjacentPipe(originPipe.getPos());
Pipe otherPipeInNetwork = findFirstAdjacentPipe(originPipe.getPos(), originPipe.getNetworkType());

if (otherPipeInNetwork != null) {
otherPipeInNetwork.getNetwork().setOriginPos(otherPipeInNetwork.getPos());
Expand All @@ -188,7 +191,7 @@ private void splitNetworks(Pipe originPipe) {
// The formNetworkAt call below can let these removed pipes join a network again.
// We only have to form a new network when necessary, hence the null check.
if (removed.getNetwork() == null) {
formNetworkAt(removed.getWorld(), removed.getPos());
formNetworkAt(removed.getWorld(), removed.getPos(), removed.getNetworkType());
}
}

Expand All @@ -202,13 +205,13 @@ private void splitNetworks(Pipe originPipe) {
}
}

private Set<Pipe> findAdjacentPipes(BlockPos pos) {
private Set<Pipe> findAdjacentPipes(BlockPos pos, ResourceLocation networkType) {
Set<Pipe> pipes = new HashSet<>();

for (Direction dir : Direction.values()) {
Pipe pipe = getPipe(pos.offset(dir));

if (pipe != null) {
if (pipe != null && pipe.getNetworkType().equals(networkType)) {
pipes.add(pipe);
}
}
Expand All @@ -217,11 +220,11 @@ private Set<Pipe> findAdjacentPipes(BlockPos pos) {
}

@Nullable
private Pipe findFirstAdjacentPipe(BlockPos pos) {
private Pipe findFirstAdjacentPipe(BlockPos pos, ResourceLocation networkType) {
for (Direction dir : Direction.values()) {
Pipe pipe = getPipe(pos.offset(dir));

if (pipe != null) {
if (pipe != null && pipe.getNetworkType().equals(networkType)) {
return pipe;
}
}
Expand All @@ -234,11 +237,6 @@ public Pipe getPipe(BlockPos pos) {
return pipes.get(pos);
}

@Nullable
public Network getNetwork(String id) {
return networks.get(id);
}

public Collection<Network> getNetworks() {
return networks.values();
}
Expand All @@ -264,8 +262,22 @@ public void read(CompoundNBT tag) {
}

ListNBT nets = tag.getList("networks", Constants.NBT.TAG_COMPOUND);
for (INBT item : nets) {
Network network = Network.fromNbt((CompoundNBT) item);
for (INBT netTag : nets) {
CompoundNBT netTagCompound = (CompoundNBT) netTag;
if (!netTagCompound.contains("type")) {
LOGGER.warn("Skipping network without type");
continue;
}

ResourceLocation type = new ResourceLocation(netTagCompound.getString("type"));

NetworkFactory factory = NetworkRegistry.INSTANCE.getFactory(type);
if (factory == null) {
LOGGER.warn("Unknown network type {}", type.toString());
continue;
}

Network network = factory.create(netTagCompound);

networks.put(network.getId(), network);
}
Expand All @@ -285,7 +297,11 @@ public CompoundNBT write(CompoundNBT tag) {
tag.put("pipes", pipes);

ListNBT networks = new ListNBT();
this.networks.values().forEach(n -> networks.add(n.writeToNbt(new CompoundNBT())));
this.networks.values().forEach(n -> {
CompoundNBT networkTag = new CompoundNBT();
networkTag.putString("type", n.getType().toString());
networks.add(n.writeToNbt(networkTag));
});
tag.put("networks", networks);

return tag;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.raoulvdberge.refinedpipes.network;

import net.minecraft.util.ResourceLocation;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;

public class NetworkRegistry {
public static final NetworkRegistry INSTANCE = new NetworkRegistry();

private final Map<ResourceLocation, NetworkFactory> factories = new HashMap<>();

private NetworkRegistry() {
}

public void addFactory(ResourceLocation type, NetworkFactory factory) {
factories.put(type, factory);
}

@Nullable
public NetworkFactory getFactory(ResourceLocation type) {
return factories.get(type);
}
}
Loading

0 comments on commit 72ba197

Please sign in to comment.