package com.hypixel.hytale.server.worldgen.cave.shape;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.HashUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.prefab.PrefabRotation;
import com.hypixel.hytale.server.core.prefab.selection.buffer.impl.IPrefabBuffer;
import com.hypixel.hytale.server.worldgen.benchmark.ChunkWorldgenBenchmark;
import com.hypixel.hytale.server.worldgen.cave.Cave;
import com.hypixel.hytale.server.worldgen.cave.CaveNodeType;
import com.hypixel.hytale.server.worldgen.cave.CaveType;
import com.hypixel.hytale.server.worldgen.cave.element.CaveNode;
import com.hypixel.hytale.server.worldgen.chunk.ChunkGenerator;
import com.hypixel.hytale.server.worldgen.chunk.ChunkGeneratorExecution;
import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabSupplier;
import com.hypixel.hytale.server.worldgen.prefab.PrefabPasteUtil;
import com.hypixel.hytale.server.worldgen.util.bounds.IChunkBounds;
import com.hypixel.hytale.server.worldgen.util.bounds.IWorldBounds;
import com.hypixel.hytale.server.worldgen.util.condition.BlockMaskCondition;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class PrefabCaveNodeShape implements CaveNodeShape, IWorldBounds {
private final CaveType caveType;
@Nonnull
private final Vector3d o;
private final Vector3d e;
@Nonnull
private final WorldGenPrefabSupplier prefabSupplier;
@Nonnull
private final PrefabRotation rotation;
private final BlockMaskCondition configuration;
private final int lowBoundX;
private final int lowBoundY;
private final int lowBoundZ;
private final int highBoundX;
private final int highBoundY;
private final int highBoundZ;
public PrefabCaveNodeShape(CaveType caveType, @Nonnull Vector3d o, Vector3d e, @Nonnull WorldGenPrefabSupplier prefabSupplier, @Nonnull PrefabRotation rotation, BlockMaskCondition configuration) {
this.caveType = caveType;
this.o = o;
this.e = e;
this.prefabSupplier = prefabSupplier;
this.rotation = rotation;
this.configuration = configuration;
IPrefabBuffer prefab = prefabSupplier.get();
IChunkBounds bounds = prefabSupplier.getBounds(prefab);
this.lowBoundX = MathUtil.floor(o.x + (double)bounds.getLowBoundX(rotation));
this.lowBoundY = MathUtil.floor(o.y + (double)prefab.getMinY());
this.lowBoundZ = MathUtil.floor(o.z + (double)bounds.getLowBoundZ(rotation));
this.highBoundX = MathUtil.ceil(o.x + (double)bounds.getHighBoundX(rotation));
this.highBoundY = MathUtil.ceil(o.y + (double)prefab.getMaxY());
this.highBoundZ = MathUtil.ceil(o.z + (double)bounds.getHighBoundZ(rotation));
}
public CaveType getCaveType() {
return this.caveType;
}
@Nonnull
public PrefabRotation getPrefabRotation() {
return this.rotation;
}
@Nonnull
public Vector3d getO() {
return this.o;
}
@Nonnull
public Vector3d getStart() {
return this.o.clone();
}
@Nonnull
public Vector3d getEnd() {
return this.o.clone().add(this.e);
}
@Nonnull
public Vector3d getAnchor(@Nonnull Vector3d vector, double tx, double ty, double tz) {
Vector3d anchor = CaveNodeShapeUtils.getBoxAnchor(vector, this, tx, ty, tz);
double x = (double)MathUtil.floor(anchor.x) + 0.5;
double y = (double)MathUtil.floor(anchor.y) + 0.5;
double z = (double)MathUtil.floor(anchor.z) + 0.5;
return anchor.assign(x, y, z);
}
@Nonnull
public IWorldBounds getBounds() {
return this;
}
public int getLowBoundX() {
return this.lowBoundX;
}
public int getLowBoundZ() {
return this.lowBoundZ;
}
public int getHighBoundX() {
return this.highBoundX;
}
public int getHighBoundZ() {
return this.highBoundZ;
}
public int getLowBoundY() {
return this.lowBoundY;
}
public int getHighBoundY() {
return this.highBoundY;
}
public boolean shouldReplace(int seed, double x, double z, int y) {
return false;
}
public double getFloorPosition(int seed, double x, double z) {
x -= this.o.x;
z -= this.o.z;
return (double)this.prefabSupplier.get().getMinYAt(this.rotation, (int)x, (int)z);
}
public double getCeilingPosition(int seed, double x, double z) {
x -= this.o.x;
z -= this.o.z;
return (double)this.prefabSupplier.get().getMaxYAt(this.rotation, (int)x, (int)z);
}
public void populateChunk(int seed, @Nonnull ChunkGeneratorExecution execution, @Nonnull Cave cave, @Nonnull CaveNode node, Random random) {
int x = MathUtil.floor(this.o.x);
int y = MathUtil.floor(this.o.y);
int z = MathUtil.floor(this.o.z);
int cx = x - ChunkUtil.minBlock(execution.getX());
int cz = z - ChunkUtil.minBlock(execution.getZ());
long externalSeed = HashUtil.hash(Double.doubleToLongBits(this.o.x), Double.doubleToLongBits(this.o.z)) * 1406794441L;
PrefabPasteUtil.PrefabPasteBuffer buffer = ChunkGenerator.getResource().prefabBuffer;
buffer.setSeed(seed, externalSeed);
buffer.execution = execution;
buffer.blockMask = this.configuration;
buffer.environmentId = node.getCaveNodeType().hasEnvironment() ? node.getCaveNodeType().getEnvironment() : this.caveType.getEnvironment();
buffer.priority = 8;
if (execution.getChunkGenerator().getBenchmark().isEnabled() && ChunkUtil.isInsideChunkRelative(cx, cz)) {
ChunkWorldgenBenchmark var10000 = execution.getChunkGenerator().getBenchmark();
String var10001 = cave.getCaveType().getName();
var10000.registerPrefab("CaveNode: " + var10001 + "\t" + node.getCaveNodeType().getName() + "\t" + this.prefabSupplier.getName());
}
PrefabPasteUtil.generate(buffer, this.rotation, this.prefabSupplier, x, y, z, cx, cz);
}
@Nonnull
public String toString() {
String var10000 = String.valueOf(this.caveType);
return "PrefabCaveNodeShape{caveType=" + var10000 + ", o=" + String.valueOf(this.o) + ", e=" + String.valueOf(this.e) + ", prefabSupplier=\"prefab\", rotation=" + String.valueOf(this.rotation) + ", configuration=" + String.valueOf(this.configuration) + ", lowBoundX=" + this.lowBoundX + ", lowBoundY=" + this.lowBoundY + ", lowBoundZ=" + this.lowBoundZ + ", highBoundX=" + this.highBoundX + ", highBoundY=" + this.highBoundY + ", highBoundZ=" + this.highBoundZ + "}";
}
public static class PrefabCaveNodeShapeGenerator implements CaveNodeShapeEnum.CaveNodeShapeGenerator {
private final List<WorldGenPrefabSupplier> prefabs;
private final BlockMaskCondition configuration;
public PrefabCaveNodeShapeGenerator(List<WorldGenPrefabSupplier> prefabs, BlockMaskCondition configuration) {
this.prefabs = prefabs;
this.configuration = configuration;
}
@Nonnull
public CaveNodeShape generateCaveNodeShape(@Nonnull Random random, CaveType caveType, @Nullable CaveNode parentNode, @Nonnull CaveNodeType.CaveNodeChildEntry childEntry, @Nonnull Vector3d origin, float yaw, float pitch) {
WorldGenPrefabSupplier prefab = (WorldGenPrefabSupplier)this.prefabs.get(random.nextInt(this.prefabs.size()));
if (parentNode == null) {
PrefabRotation rotation = PrefabRotation.VALUES[random.nextInt(PrefabRotation.VALUES.length)];
return new PrefabCaveNodeShape(caveType, origin, Vector3d.ZERO, prefab, rotation, this.configuration);
} else {
Vector3d offset = childEntry.getOffset().clone();
PrefabRotation rotation = childEntry.getRotation(random);
CaveNodeShape var12 = parentNode.getShape();
if (var12 instanceof PrefabCaveNodeShape) {
PrefabCaveNodeShape parentShape = (PrefabCaveNodeShape)var12;
PrefabRotation parentRotation = parentShape.getPrefabRotation();
parentRotation.rotate(offset);
rotation = rotation.add(parentRotation);
}
origin.add(offset);
return new PrefabCaveNodeShape(caveType, origin, Vector3d.ZERO, prefab, rotation, this.configuration);
}
}
}
}