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;
|
if (level.isClientSide) return;
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
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();
|
long endTime = System.currentTimeMillis();
|
||||||
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
LOGGER.info("Discovery took " + (endTime - startTime) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Direction, BlockPos> getValidTransitionsFrom(BlockPos pos, Direction incoming, Level level, Set<BlockPos> visited) {
|
private Set<Transition> getValidTransitionsFrom(NetworkState state, Level level) {
|
||||||
Map<Direction, BlockPos> dirs = new EnumMap<>(Direction.class);
|
Set<Transition> dirs = new HashSet<>();
|
||||||
for (Direction dir : Direction.values()) {
|
for (Direction dir : Direction.values()) {
|
||||||
if (incoming != null && dir == incoming) continue;
|
if (state.lastTransition != null && dir == state.lastTransition) continue;
|
||||||
BlockPos newPos = pos.relative(dir);
|
BlockPos newPos = state.currentPos.relative(dir);
|
||||||
if (visited.contains(newPos)) continue;
|
if (state.visited.contains(newPos)) continue;
|
||||||
if (VALID_COOLANT_BLOCKS.contains(level.getBlockState(newPos).getBlock())) dirs.put(dir, newPos);
|
if (VALID_COOLANT_BLOCKS.contains(level.getBlockState(newPos).getBlock())) dirs.add(new Transition(dir, newPos, level.getBlockState(newPos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirs;
|
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) {
|
private String getBlockName(Block block) {
|
||||||
return block.getName().getContents().toString();
|
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