package com.hypixel.hytale.builtin.hytalegenerator.props.filler;
import com.hypixel.hytale.builtin.hytalegenerator.MaterialSet;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize;
import com.hypixel.hytale.builtin.hytalegenerator.conveyor.stagedconveyor.ContextDependency;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.ArrayVoxelSpace;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.VoxelSpace;
import com.hypixel.hytale.builtin.hytalegenerator.material.Material;
import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider;
import com.hypixel.hytale.builtin.hytalegenerator.newsystem.TerrainDensityProvider;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern;
import com.hypixel.hytale.builtin.hytalegenerator.props.Prop;
import com.hypixel.hytale.builtin.hytalegenerator.scanners.Scanner;
import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer;
import com.hypixel.hytale.math.vector.Vector3i;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
public class PondFillerProp extends Prop {
private static final int TRAVERSED = 1;
private static final int LEAKS = 16;
private static final int SOLID = 256;
private static final int STACKED = 4096;
private final Vector3i boundingMin;
private final Vector3i boundingMax;
private final MaterialProvider<Material> filledMaterialProvider;
private final MaterialSet solidSet;
private final Scanner scanner;
private final Pattern pattern;
private final ContextDependency contextDependency;
private final Bounds3i writeBounds_voxelGrid;
public PondFillerProp(@Nonnull Vector3i boundingMin, @Nonnull Vector3i boundingMax, @Nonnull MaterialSet solidSet, @Nonnull MaterialProvider<Material> filledMaterialProvider, @Nonnull Scanner scanner, @Nonnull Pattern pattern) {
this.boundingMin = boundingMin.clone();
this.boundingMax = boundingMax.clone();
this.solidSet = solidSet;
this.filledMaterialProvider = filledMaterialProvider;
this.scanner = scanner;
this.pattern = pattern;
SpaceSize boundingSpace = new SpaceSize(boundingMin, boundingMax);
boundingSpace = SpaceSize.stack(boundingSpace, scanner.readSpaceWith(pattern));
SpaceSize.stack(scanner.readSpaceWith(pattern), boundingSpace);
Vector3i range = boundingSpace.getRange();
this.contextDependency = new ContextDependency(range, range);
this.writeBounds_voxelGrid = this.contextDependency.getTotalPropBounds_voxelGrid();
}
public FillerPropScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace<Material> materialSpace, @Nonnull WorkerIndexer.Id id) {
Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id);
List<Vector3i> scanResults = this.scanner.scan(scannerContext);
if (scanResults.size() == 1) {
List<Vector3i> resultList = this.renderFluidBlocks((Vector3i)scanResults.getFirst(), materialSpace);
return new FillerPropScanResult(resultList);
} else {
ArrayList<Vector3i> resultList = new ArrayList();
for(Vector3i scanPosition : scanResults) {
List<Vector3i> renderResult = this.renderFluidBlocks(scanPosition, materialSpace);
resultList.addAll(renderResult);
}
return new FillerPropScanResult(resultList);
}
}
private List<Vector3i> renderFluidBlocks(@Nonnull Vector3i origin, @Nonnull VoxelSpace<Material> materialSpace) {
Vector3i min = this.boundingMin.clone().add(origin);
Vector3i max = this.boundingMax.clone().add(origin);
min = Vector3i.max(min, new Vector3i(materialSpace.minX(), materialSpace.minY(), materialSpace.minZ()));
max = Vector3i.min(max, new Vector3i(materialSpace.maxX(), materialSpace.maxY(), materialSpace.maxZ()));
ArrayVoxelSpace<Integer> mask = new ArrayVoxelSpace<Integer>(max.x - min.x, max.y - min.y, max.z - min.z);
mask.setOrigin(-min.x, -min.y, -min.z);
mask.set(0);
int y = min.y;
for(int x = min.x; x < max.x; ++x) {
for(int z = min.z; z < max.z; ++z) {
Material material = materialSpace.getContent(x, y, z);
int contextMaterialHash = material.hashMaterialIds();
int maskValue = 1;
if (this.solidSet.test(contextMaterialHash)) {
maskValue |= 256;
mask.set(maskValue, x, y, z);
} else {
maskValue |= 16;
mask.set(maskValue, x, y, z);
}
}
}
for(int var29 = min.y + 1; var29 < max.y; ++var29) {
int underY = var29 - 1;
for(int x = min.x; x < max.x; ++x) {
for(int z = min.z; z < max.z; ++z) {
if (!isTraversed((Integer)mask.getContent(x, var29, z))) {
int maskValueUnder = (Integer)mask.getContent(x, underY, z);
Material material = materialSpace.getContent(x, var29, z);
int contextMaterialHash = material.hashMaterialIds();
if (this.solidSet.test(contextMaterialHash)) {
int maskValue = 0;
maskValue |= 1;
maskValue |= 256;
mask.set(maskValue, x, var29, z);
} else if (isLeaks(maskValueUnder) || x == min.x || x == max.x - 1 || z == min.z || z == max.z - 1) {
ArrayDeque<Vector3i> stack = new ArrayDeque();
stack.push(new Vector3i(x, var29, z));
mask.set(4096, x, var29, z);
Vector3i poppedPos;
for(; !stack.isEmpty(); --poppedPos.z) {
poppedPos = (Vector3i)stack.pop();
int maskValue = (Integer)mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
maskValue |= 16;
mask.set(maskValue, poppedPos.x, poppedPos.y, poppedPos.z);
--poppedPos.x;
if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
int poppedMaskValue = (Integer)mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
if (!isStacked(poppedMaskValue)) {
material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
contextMaterialHash = material.hashMaterialIds();
if (!this.solidSet.test(contextMaterialHash)) {
stack.push(poppedPos.clone());
mask.set(4096 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
}
}
}
poppedPos.x += 2;
if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
int poppedMaskValue = (Integer)mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
if (!isStacked(poppedMaskValue)) {
material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
contextMaterialHash = material.hashMaterialIds();
if (!this.solidSet.test(contextMaterialHash)) {
stack.push(poppedPos.clone());
mask.set(4096 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
}
}
}
--poppedPos.x;
--poppedPos.z;
if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
int poppedMaskValue = (Integer)mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
if (!isStacked(poppedMaskValue)) {
material = materialSpace.getContent(poppedPos.x, var29, poppedPos.z);
contextMaterialHash = material.hashMaterialIds();
if (!this.solidSet.test(contextMaterialHash)) {
stack.push(poppedPos.clone());
mask.set(4096 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
}
}
}
poppedPos.z += 2;
if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
int poppedMaskValue = (Integer)mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
if (!isStacked(poppedMaskValue)) {
material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
contextMaterialHash = material.hashMaterialIds();
if (!this.solidSet.test(contextMaterialHash)) {
stack.push(poppedPos.clone());
mask.set(4096 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
}
}
}
}
}
}
}
}
}
ArrayList<Vector3i> fluidBlocks = new ArrayList();
for(int var30 = mask.minY() + 1; var30 < mask.maxY(); ++var30) {
for(int x = mask.minX() + 1; x < mask.maxX() - 1; ++x) {
for(int z = mask.minZ() + 1; z < mask.maxZ() - 1; ++z) {
int maskValue = (Integer)mask.getContent(x, var30, z);
if (!isSolid(maskValue) && !isLeaks(maskValue)) {
fluidBlocks.add(new Vector3i(x, var30, z));
}
}
}
}
return fluidBlocks;
}
public void place(@Nonnull Prop.Context context) {
List<Vector3i> fluidBlocks = FillerPropScanResult.cast(context.scanResult).getFluidBlocks();
if (fluidBlocks != null) {
for(Vector3i position : fluidBlocks) {
if (context.materialSpace.isInsideSpace(position.x, position.y, position.z)) {
MaterialProvider.Context materialsContext = new MaterialProvider.Context(position, 0.0, 0, 0, 0, 0, context.workerId, (TerrainDensityProvider)null, context.distanceFromBiomeEdge);
Material material = this.filledMaterialProvider.getVoxelTypeAt(materialsContext);
if (material != null) {
context.materialSpace.set(material, position.x, position.y, position.z);
}
}
}
}
}
public ContextDependency getContextDependency() {
return this.contextDependency.clone();
}
@Nonnull
public Bounds3i getWriteBounds() {
return this.writeBounds_voxelGrid;
}
private static boolean isTraversed(int maskValue) {
return (maskValue & 1) == 1;
}
private static boolean isLeaks(int maskValue) {
return (maskValue & 16) == 16;
}
private static boolean isSolid(int maskValue) {
return (maskValue & 256) == 256;
}
private static boolean isStacked(int maskValue) {
return (maskValue & 4096) == 4096;
}
}