package Hexel.blocks.rules;
import java.util.ArrayList;
import Hexel.blocks.BlockDelta;
import Hexel.blocks.BlockRule;
import Hexel.blocks.BlockRules;
import Hexel.blocks.BlockSimulator;
import Hexel.blocks.BlockSimulator.BlockDeltaAdder;
import Hexel.blocks.BlockTools;
import Hexel.blocks.BlockTools.PointFloodSearchMatcher;
import Hexel.blocks.FreqBlockRule;
import Hexel.blocks.types.Block;
import Hexel.blocks.types.BlockEmpty;
import Hexel.blocks.types.BlockTransparent;
import Hexel.blocks.types.BlockWater;
import Hexel.chunk.Chunk;
import Hexel.chunk.Chunks;
import Hexel.chunk.HighestBlockChunk;
import Hexel.math.HexGeometry;
import Hexel.math.Vector2i;
import Hexel.math.Vector3i;
import Hexel.util.Container;
import Hexel.util.Pair;
public class WatermoveRule extends FreqBlockRule {
public WatermoveRule() {
super(5);
}
private Vector3i tmp3i = new Vector3i();
private int numSeen = 0;
private Container<Vector3i> lowestWaterPoint = new Container<Vector3i>();
private Container<Integer> lowestWaterLevel = new Container<Integer>();
private boolean checkAgain;
@Override
public int freqRun(int bx, int by, final int bz, boolean fastMode, Block b, final Chunk c,
HighestBlockChunk hbc, final Chunks chunks, int step, final BlockDeltaAdder blockDeltaAdder) {
BlockWater bw = (BlockWater)b;
final Vector3i start = new Vector3i(bx, by, bz);
checkAgain = false;
numSeen = 0;
final int startWaterLevel = bz*8 + bw.getTop();
lowestWaterLevel.contents = Integer.MAX_VALUE;
lowestWaterPoint.contents = null;
// System.out.println("HWG " + step);
BlockTools.pointFloodSearch(start, new BlockTools.PointFloodSearchMatcher() {
@Override
public boolean matches(Vector3i p) {
Block b = chunks.getBlock(p.x, p.y, p.z, tmp3i, c);
if (numSeen > 100){
return false;
}
// if (b instanceof BlockEmpty && p.z == bz) {
// Block bl = chunks.getBlock(p.x, p.y, p.z - 1, tmp3i, c);
// if (bl instanceof BlockEmpty || bl instanceof BlockWater) {
// b = bl;
// p.z -= 1;
// }
// }
int waterLevel;
if (b instanceof BlockWater || b instanceof BlockEmpty){
if (b instanceof BlockWater){
numSeen += 1;
int blockWaterLevel = 0;
BlockWater wb = (BlockWater) b;
if (wb.getBottom() != 0){
blockWaterLevel = wb.getBottom();
}
else if (wb.getTop() < 8) {
blockWaterLevel = wb.getTop();
}
waterLevel = p.z*8 + blockWaterLevel;
}
else {
waterLevel = p.z*8;
}
if (startWaterLevel > waterLevel){
if (!blockDeltaAdder.hasBlockDelta(p)){
if (lowestWaterPoint.contents == null){
lowestWaterPoint.contents = p;
lowestWaterLevel.contents = waterLevel;
}
else if (waterLevel < lowestWaterLevel.contents){
lowestWaterPoint.contents = p;
lowestWaterLevel.contents = waterLevel;
}
else if (waterLevel == lowestWaterLevel.contents){
double currDist = lowestWaterPoint.contents.distance(start);
double nextDist = p.distance(start);
if (nextDist < currDist){
lowestWaterPoint.contents = p;
lowestWaterLevel.contents = waterLevel;
}
}
}
else {
checkAgain = true;
}
if (b instanceof BlockWater)
return true;
}
}
return false;
}
});
if (lowestWaterPoint.contents != null){
BlockTransparent lowestWaterBlock = (BlockTransparent)chunks.getBlock(
lowestWaterPoint.contents.x,
lowestWaterPoint.contents.y,
lowestWaterPoint.contents.z, tmp3i, c);
int waterLevelDiff = startWaterLevel - lowestWaterLevel.contents;
int toMove = Math.min(waterLevelDiff/2, bw.getTop() - bw.getBottom());
if (toMove > 0){
if (toMove == bw.getTop() - bw.getBottom()){
blockDeltaAdder.addBlockDelta(BlockDelta.Aquire(bx, by, bz, BlockEmpty.Make(bw.naturalLightLevel),
chunks.getStepsToSim(bx, by, bz, tmp3i, c)));
}
else {
blockDeltaAdder.addBlockDelta(BlockDelta.Aquire(bx, by, bz,
BlockWater.Make(bw.naturalLightLevel, 0, (bw.getTop() - bw.getBottom()) - toMove),
chunks.getStepsToSim(bx, by, bz, tmp3i, c)));
}
blockDeltaAdder.addBlockDelta(BlockDelta.Aquire(
lowestWaterPoint.contents.x,
lowestWaterPoint.contents.y,
lowestWaterPoint.contents.z,
BlockWater.Make(lowestWaterBlock.naturalLightLevel, 0, toMove),
chunks.getStepsToSim(bx, by, bz, tmp3i, c)));
}
}
if (checkAgain)
return 1;
else
return BlockSimulator.DONT_RUN;
}
}