coolant logic refactor
This commit is contained in:
parent
8da40906e6
commit
7072a25ac4
|
@ -28,135 +28,164 @@ public class CoolantBaseBlock extends Block {
|
|||
if (level.isClientSide) return;
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
boolean encounteredMetering = false;
|
||||
boolean encounteredCompressor = false;
|
||||
boolean encounteredHeatSpreader = false;
|
||||
Set<BlockPos> visitedBlocks = new HashSet<>();
|
||||
// If we happened to choose the path that encounters the metering device before a heat spreader, we need to swap our detection system.
|
||||
boolean prematureMetering = false;
|
||||
Direction lastTransitionDirection;
|
||||
|
||||
LOGGER.info("Beginning network discovery");
|
||||
searchForValidNetwork(new BlockPos.MutableBlockPos(pos.getX(), pos.getY(), pos.getZ()), level);
|
||||
|
||||
// Get the valid directions we can go.
|
||||
var dirs = getValidTransitionsFrom(pos, null, level, visitedBlocks);
|
||||
|
||||
LOGGER.info("First step: " + dirs.size() + " valid moves.");
|
||||
// If we aren't connected to at least 2 other valid blocks, it is impossible to have a completed network.
|
||||
if (dirs.size() < 2) {
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
};
|
||||
|
||||
// Check the block we're at, first.
|
||||
if (this == Blocks.COMPRESSOR_BLOCK.block().get()) encounteredCompressor = true;
|
||||
else if (this == Blocks.COOLANT_METERING_BLOCK.block().get()) { encounteredMetering = true; prematureMetering = true; }
|
||||
else if (this == Blocks.COOLANT_HEAT_SPREADER_BLOCK.block().get()) encounteredHeatSpreader = true;
|
||||
|
||||
visitedBlocks.add(pos);
|
||||
while (dirs.size() > 1) {
|
||||
// Traverse the new block
|
||||
lastTransitionDirection = (Direction) dirs.keySet().toArray()[0];
|
||||
BlockPos traversedPos = dirs.get(lastTransitionDirection);
|
||||
|
||||
Block reachedBlock = level.getBlockState(traversedPos).getBlock();
|
||||
|
||||
LOGGER.info("Traversing through " + lastTransitionDirection + " to " + traversedPos + ", which is a " + getBlockName(reachedBlock));
|
||||
visitedBlocks.add(traversedPos);
|
||||
|
||||
// If we reached a metering block for the first time
|
||||
if (reachedBlock == Blocks.COOLANT_METERING_BLOCK.block().get()) {
|
||||
if (encounteredMetering) {
|
||||
LOGGER.info("Two metering devices in the same network! Not valid.");
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
}
|
||||
// And we have already reached a heat spreader:
|
||||
if (encounteredHeatSpreader) {
|
||||
// Tell the system to check for another
|
||||
encounteredHeatSpreader = false;
|
||||
// Set the metering flag true
|
||||
} else {
|
||||
// We're searching prematurely!
|
||||
// We'll search for it at the compressor instead.
|
||||
prematureMetering = true;
|
||||
}
|
||||
encounteredMetering = true;
|
||||
// The compressor has its own things to check..
|
||||
} else if (reachedBlock == Blocks.COMPRESSOR_BLOCK.block().get()) {
|
||||
if (encounteredCompressor) {
|
||||
LOGGER.info("Two compressors in the same network! Not valid.");
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
}
|
||||
|
||||
// Premature metering means we should check that a heat spreader is between the metering device and the compressor.
|
||||
if (prematureMetering) {
|
||||
if (!encounteredHeatSpreader) {
|
||||
LOGGER.info("Metering Device and Compressor are too close together! Not valid.");
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
} else {
|
||||
encounteredCompressor = true;
|
||||
}
|
||||
} else {
|
||||
encounteredCompressor = true;
|
||||
}
|
||||
// Heat spreaders may have many, so we just flip the flag to be true if we're just getting to one now.
|
||||
} else if (reachedBlock == Blocks.COOLANT_HEAT_SPREADER_BLOCK.block().get()) {
|
||||
if (!encounteredHeatSpreader) encounteredHeatSpreader = true;
|
||||
}
|
||||
|
||||
dirs = getValidTransitionsFrom(traversedPos, lastTransitionDirection, level, visitedBlocks);
|
||||
}
|
||||
|
||||
// Try to finalise stuff - we gotta have everything in our network.
|
||||
// First, check that the last remaining direction takes us into a block we've already visited (the closed loop)
|
||||
if (visitedBlocks.contains(dirs.values().iterator().next())) {
|
||||
// Check for premature mode
|
||||
if (prematureMetering) {
|
||||
if (!(encounteredCompressor && encounteredHeatSpreader)) {
|
||||
LOGGER.info("Two heat spreaders not found in valid configuration!");
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!(encounteredCompressor && encounteredMetering && encounteredHeatSpreader)) {
|
||||
LOGGER.info("Not encountered all components of the coolant system!");
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info("Valid coolant loop!");
|
||||
long endTime = System.currentTimeMillis();
|
||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||
}
|
||||
|
||||
private Map<Direction, BlockPos> getValidTransitionsFrom(BlockPos pos, Direction incoming, Level level, Set<BlockPos> visited) {
|
||||
Map<Direction, BlockPos> dirs = new EnumMap<>(Direction.class);
|
||||
private Set<Transition> getValidTransitionsFrom(NetworkState state, Level level) {
|
||||
Set<Transition> dirs = new HashSet<>();
|
||||
for (Direction dir : Direction.values()) {
|
||||
if (incoming != null && dir == incoming) continue;
|
||||
BlockPos newPos = pos.relative(dir);
|
||||
if (visited.contains(newPos)) continue;
|
||||
if (VALID_COOLANT_BLOCKS.contains(level.getBlockState(newPos).getBlock())) dirs.put(dir, newPos);
|
||||
if (state.lastTransition != null && dir == state.lastTransition) continue;
|
||||
BlockPos newPos = state.currentPos.relative(dir);
|
||||
if (state.visited.contains(newPos)) continue;
|
||||
if (VALID_COOLANT_BLOCKS.contains(level.getBlockState(newPos).getBlock())) dirs.add(new Transition(dir, newPos, level.getBlockState(newPos)));
|
||||
}
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Revert the search to a known good state
|
||||
private boolean searchForValidNetwork(BlockPos.MutableBlockPos pos, Level level) {
|
||||
NetworkState state = new NetworkState(false, false, false, new HashSet<>(), false, null, pos);
|
||||
Queue<StateTransitions> queue = new ArrayDeque<>();
|
||||
|
||||
LOGGER.info("Beginning network discovery");
|
||||
|
||||
// Get the valid directions we can go.
|
||||
var dirs = getValidTransitionsFrom(state, level);
|
||||
|
||||
LOGGER.info("First step: " + dirs.size() + " valid moves.");
|
||||
// If we aren't connected to at least 2 other valid blocks, it is impossible to have a completed network.
|
||||
if (dirs.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.visited.add(pos);
|
||||
|
||||
queue.add(new StateTransitions(state.copy(), dirs));
|
||||
|
||||
// Check the block we're at, first.
|
||||
if (this == Blocks.COMPRESSOR_BLOCK.block().get()) state.compressor = true;
|
||||
else if (this == Blocks.COOLANT_METERING_BLOCK.block().get()) { state.metering = true; state.premature = true; }
|
||||
else if (this == Blocks.COOLANT_HEAT_SPREADER_BLOCK.block().get()) state.spreader = true;
|
||||
|
||||
while(!queue.isEmpty()) {
|
||||
// The search loop
|
||||
search(queue.element(), level, queue);
|
||||
|
||||
// Try to finalise stuff - we gotta have everything in our network.
|
||||
// First, check that the last remaining direction takes us into a block we've already visited (the closed loop)
|
||||
if (state.visited.contains(dirs.iterator().next().pos())) {
|
||||
// Check for premature mode
|
||||
if (state.premature) {
|
||||
if (!(state.compressor && state.spreader)) {
|
||||
LOGGER.info("Two heat spreaders not found in valid configuration!");
|
||||
queue.poll();
|
||||
}
|
||||
} else {
|
||||
if (!(state.compressor && state.metering && state.spreader)) {
|
||||
LOGGER.info("Not encountered all components of the coolant system!");
|
||||
queue.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info("Valid coolant loop!");
|
||||
return true;
|
||||
}
|
||||
|
||||
void search(StateTransitions st, Level level, Queue<StateTransitions> queue) {
|
||||
while (st.transitions.size() > 1) {
|
||||
// Traverse the new block
|
||||
Transition transition = st.transitions.iterator().next();
|
||||
st.state.lastTransition = transition.dir();
|
||||
st.state.currentPos = transition.pos();
|
||||
|
||||
Block reachedBlock = transition.state().getBlock();
|
||||
|
||||
LOGGER.info("Traversing through " + st.state.lastTransition + " to " + st.state.currentPos + ", which is a " + getBlockName(reachedBlock));
|
||||
st.state.visited.add(st.state.currentPos);
|
||||
|
||||
// If we reached a metering block for the first time
|
||||
if (reachedBlock == Blocks.COOLANT_METERING_BLOCK.block().get()) {
|
||||
st.state.metering();
|
||||
// The compressor has its own things to check..
|
||||
} else if (reachedBlock == Blocks.COMPRESSOR_BLOCK.block().get()) {
|
||||
st.state.compressor();
|
||||
// Heat spreaders may have many, so we just flip the flag to be true if we're just getting to one now.
|
||||
} else if (reachedBlock == Blocks.COOLANT_HEAT_SPREADER_BLOCK.block().get()) {
|
||||
if (!st.state.spreader) st.state.spreader = true;
|
||||
}
|
||||
|
||||
Set<Transition> newTransitions = getValidTransitionsFrom(st.state, level);
|
||||
queue.add(new StateTransitions(st.state.copy(), newTransitions));
|
||||
}
|
||||
}
|
||||
|
||||
private String getBlockName(Block block) {
|
||||
return block.getName().getContents().toString();
|
||||
}
|
||||
|
||||
record Transition(Direction dir, BlockPos pos, BlockState state) {}
|
||||
|
||||
static class NetworkState {
|
||||
boolean metering, compressor, spreader, premature;
|
||||
Set<BlockPos> visited;
|
||||
Direction lastTransition;
|
||||
BlockPos currentPos;
|
||||
|
||||
public NetworkState(boolean metering, boolean compressor, boolean spreader, HashSet<BlockPos> visited, boolean premature, Direction lastTransition, BlockPos pos) {
|
||||
this.metering = metering;
|
||||
this.compressor = compressor;
|
||||
this.spreader = spreader;
|
||||
this.premature = premature;
|
||||
this.visited = visited;
|
||||
this.lastTransition = lastTransition;
|
||||
this.currentPos = pos;
|
||||
}
|
||||
|
||||
void metering() {
|
||||
if (metering)
|
||||
LOGGER.info("Two metering devices in the same network! Not valid.");
|
||||
|
||||
// And we have already reached a heat spreader:
|
||||
if (spreader) {
|
||||
// Tell the system to check for another
|
||||
spreader = false;
|
||||
// Set the metering flag true
|
||||
} else {
|
||||
// We're searching prematurely!
|
||||
// We'll search for it at the compressor instead.
|
||||
premature = true;
|
||||
}
|
||||
metering = true;
|
||||
}
|
||||
|
||||
void compressor() {
|
||||
if (compressor)
|
||||
LOGGER.info("Two compressors in the same network! Not valid.");
|
||||
|
||||
// Premature metering means we should check that a heat spreader is between the metering device and the compressor.
|
||||
if (premature) {
|
||||
if (!spreader) {
|
||||
LOGGER.info("Metering Device and Compressor are too close together! Not valid.");
|
||||
} else {
|
||||
compressor = true;
|
||||
}
|
||||
} else {
|
||||
compressor = true;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkState copy() {
|
||||
return new NetworkState(metering, compressor, spreader, new HashSet<>(visited), premature, lastTransition, currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
record StateTransitions(NetworkState state, Set<Transition> transitions) {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user