classpublicPriority 3
CaveGenerator
com.hypixel.hytale.server.worldgen.cave.CaveGenerator
2
Methods
2
Public Methods
1
Fields
1
Constructors
Constructors
public
CaveGenerator(CaveType[] caveTypes)Methods
Public Methods (2)
public
Cave generate(int seed, ChunkGenerator chunkGenerator, CaveType caveType, int x, int y, int z)@Nonnull
public
CaveType[] getCaveTypes()Fields
Private/Package Fields (1)
private
CaveType[] caveTypesRelated Classes
Source Code
package com.hypixel.hytale.server.worldgen.cave;
import com.hypixel.hytale.math.util.FastRandom;
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.procedurallib.condition.ConstantIntCondition;
import com.hypixel.hytale.procedurallib.condition.DefaultCoordinateCondition;
import com.hypixel.hytale.procedurallib.condition.ICoordinateCondition;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import com.hypixel.hytale.procedurallib.supplier.IDoubleRange;
import com.hypixel.hytale.server.core.prefab.PrefabRotation;
import com.hypixel.hytale.server.worldgen.cave.element.CaveNode;
import com.hypixel.hytale.server.worldgen.cave.element.CavePrefab;
import com.hypixel.hytale.server.worldgen.cave.prefab.CavePrefabContainer;
import com.hypixel.hytale.server.worldgen.cave.shape.CaveNodeShape;
import com.hypixel.hytale.server.worldgen.cave.shape.PrefabCaveNodeShape;
import com.hypixel.hytale.server.worldgen.chunk.ChunkGenerator;
import com.hypixel.hytale.server.worldgen.chunk.ZoneBiomeResult;
import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabSupplier;
import com.hypixel.hytale.server.worldgen.util.ArrayUtli;
import com.hypixel.hytale.server.worldgen.util.condition.flag.Int2FlagsCondition;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class CaveGenerator {
private final CaveType[] caveTypes;
public CaveGenerator(CaveType[] caveTypes) {
this.caveTypes = caveTypes;
}
public CaveType[] getCaveTypes() {
return this.caveTypes;
}
@Nonnull
public Cave generate(int seed, @Nonnull ChunkGenerator chunkGenerator, @Nonnull CaveType caveType, int x, int y, int z) {
int seedOffset = (int)HashUtil.rehash((long)seed, (long)x, (long)y, (long)z);
Random random = new FastRandom((long)seedOffset);
Cave cave = this.newCave(caveType);
Vector3d origin = new Vector3d((double)x, (double)y, (double)z);
origin.y = (double)caveType.getModifiedStartHeight(seed + seedOffset, x, y, z, random);
this.startCave(seed, chunkGenerator, cave, origin, random);
cave.compile();
return cave;
}
@Nonnull
protected Cave newCave(CaveType caveType) {
return new Cave(caveType);
}
protected void startCave(int seed, @Nonnull ChunkGenerator chunkGenerator, @Nonnull Cave cave, @Nonnull Vector3d origin, @Nonnull Random random) {
Int2FlagsCondition biomeMask = cave.getCaveType().getBiomeMask();
int startBiomeMaskResult = this.getBiomeMaskResult(seed, chunkGenerator, biomeMask, origin);
if (CaveBiomeMaskFlags.canGenerate(startBiomeMaskResult)) {
CaveType caveType = cave.getCaveType();
int depth = caveType.getStartDepth(random);
CaveNodeType type = caveType.getEntryNode();
float yaw = caveType.getStartYaw(random);
float pitch = caveType.getStartPitch(random);
int seedOffset = random.nextInt();
CaveNodeShape shape = type.generateCaveNodeShape(random, caveType, null, null, origin, yaw, pitch);
int endBiomeMaskResult = this.getBiomeMaskResult(seed, chunkGenerator, biomeMask, shape.getEnd());
if (CaveBiomeMaskFlags.canGenerate(endBiomeMaskResult)) {
CaveNode node = new CaveNode(seed + seedOffset, type, shape, yaw, pitch);
if (shape.hasGeometry() && CaveBiomeMaskFlags.canPopulate(startBiomeMaskResult) && CaveBiomeMaskFlags.canPopulate(endBiomeMaskResult)) {
cave.addNode(node);
}
this.continueNode(seed, chunkGenerator, cave, node, depth, random);
}
}
}
protected void continueNode(
int seed, @Nonnull ChunkGenerator chunkGenerator, @Nonnull Cave cave, @Nonnull CaveNode parent, int depth, @Nonnull Random random
) {
if (depth > 0) {
Int2FlagsCondition biomeMask = cave.getCaveType().getBiomeMask();
CaveNodeType.CaveNodeChildEntry[] childEntries = this.getChildEntriesRandomized(parent.getCaveNodeType(), random);
int childrenCount = this.getChildrenCount(parent.getCaveNodeType(), random);
int generatedChildren = 0;
for (CaveNodeType.CaveNodeChildEntry childEntry : childEntries) {
int repeat = this.getRepeatCounter(childEntry, random);
for (int j = 0; j < repeat; j++) {
if (this.shouldGenerateChild(childEntry, random)) {
if (generatedChildren >= childrenCount) {
return;
}
PrefabRotation parentRotation = this.getRotation(parent);
Vector3d origin = this.getChildOrigin(parent, parentRotation, childEntry);
CaveNodeType type = childEntry.getTypes().get(random);
if (this.isMatchingHeight(seed, origin, type.getHeightCondition())) {
float yaw = this.getChildYaw(parent, parentRotation, childEntry, random);
float pitch = childEntry.getPitchModifier().calc(parent.getPitch(), random);
int hash = random.nextInt();
CaveNodeShape shape = type.generateCaveNodeShape(random, cave.getCaveType(), parent, childEntry, origin, yaw, pitch);
if (this.isMatchingHeight(seed, shape.getEnd(), type.getHeightCondition())) {
int biomeMaskResult = this.getBiomeMaskResult(seed, chunkGenerator, biomeMask, shape.getEnd());
if (!CaveBiomeMaskFlags.canGenerate(biomeMaskResult)) {
if (!CaveBiomeMaskFlags.canContinue(biomeMaskResult)) {
break;
}
} else {
CaveNode node = new CaveNode(hash, type, shape, yaw, pitch);
if (shape.hasGeometry() && CaveBiomeMaskFlags.canPopulate(biomeMaskResult)) {
this.generatePrefabs(seed, chunkGenerator, parent, node);
cave.addNode(node);
}
int nextDepth = this.getNextDepth(childEntry, depth, random);
this.continueNode(seed, chunkGenerator, cave, node, nextDepth, random);
generatedChildren++;
}
}
}
}
}
}
}
}
protected int getChildrenCount(@Nonnull CaveNodeType type, Random random) {
IDoubleRange countArray = type.getChildrenCountBounds();
return countArray == null ? 2147483647 : MathUtil.floor(countArray.getValue(random));
}
@Nonnull
protected CaveNodeType.CaveNodeChildEntry[] getChildEntriesRandomized(@Nonnull CaveNodeType type, @Nonnull Random random) {
CaveNodeType.CaveNodeChildEntry[] childEntries = type.getChildren();
if (type.getChildrenCountBounds() != null && childEntries.length != 0) {
CaveNodeType.CaveNodeChildEntry[] randomized = new CaveNodeType.CaveNodeChildEntry[childEntries.length];
System.arraycopy(childEntries, 0, randomized, 0, randomized.length);
ArrayUtli.shuffleArray((CaveNodeType.CaveNodeChildEntry[])randomized, random);
return randomized;
} else {
return childEntries;
}
}
protected int getRepeatCounter(@Nonnull CaveNodeType.CaveNodeChildEntry entry, Random random) {
return MathUtil.floor(entry.getRepeat().getValue(random));
}
@Nullable
protected PrefabRotation getRotation(@Nonnull CaveNode caveNode) {
CaveNodeShape shape = caveNode.getShape();
return shape instanceof PrefabCaveNodeShape ? ((PrefabCaveNodeShape)shape).getPrefabRotation() : null;
}
protected Vector3d getChildOrigin(@Nonnull CaveNode parentNode, @Nullable PrefabRotation parentRotation, @Nonnull CaveNodeType.CaveNodeChildEntry childEntry) {
Vector3d vector = parentNode.getEnd();
Vector3d anchor = childEntry.getAnchor();
if (anchor == Vector3d.ZERO) {
return vector;
} else {
vector.assign(anchor);
if (parentRotation != null && parentRotation != PrefabRotation.ROTATION_0) {
vector.subtract(0.5, 0.5, 0.5);
parentRotation.rotate(vector);
vector.add(0.5, 0.5, 0.5);
}
return parentNode.getShape().getAnchor(vector, vector.x, vector.y, vector.z);
}
}
protected float getChildYaw(
@Nonnull CaveNode parentNode, @Nullable PrefabRotation parentRotation, @Nonnull CaveNodeType.CaveNodeChildEntry childEntry, Random random
) {
float yaw = childEntry.getYawMode().combine(parentNode.getYaw(), parentRotation);
return childEntry.getYawModifier().calc(yaw, random);
}
protected boolean shouldGenerateChild(@Nonnull CaveNodeType.CaveNodeChildEntry entry, @Nonnull Random random) {
return random.nextDouble() < entry.getChance();
}
protected boolean isMatchingHeight(int seed, @Nonnull Vector3d vec, @Nonnull ICoordinateCondition condition) {
if (condition == DefaultCoordinateCondition.DEFAULT_TRUE) {
return true;
} else if (condition == DefaultCoordinateCondition.DEFAULT_FALSE) {
return false;
} else {
int x = MathUtil.floor(vec.x);
int y = MathUtil.floor(vec.y);
int z = MathUtil.floor(vec.z);
return condition.eval(seed, x, y, z);
}
}
protected int getNextDepth(@Nonnull CaveNodeType.CaveNodeChildEntry entry, int depth, Random random) {
int nextDepth = depth - 1;
if (entry.getChildrenLimit() != null) {
int limit = MathUtil.floor(entry.getChildrenLimit().getValue(random));
if (limit < nextDepth) {
return limit;
}
}
return nextDepth;
}
protected void generatePrefabs(int seed, @Nonnull ChunkGenerator chunkGenerator, CaveNode parent, @Nonnull CaveNode node) {
Random random = ChunkGenerator.getResource().getRandom();
random.setSeed((long)(seed + node.getSeedOffset()));
CavePrefabContainer container = node.getCaveNodeType().getPrefabContainer();
if (container != null) {
for (CavePrefabContainer.CavePrefabEntry entry : container.getEntries()) {
this.generatePrefab(seed, chunkGenerator, parent, node, entry, random);
}
}
}
protected void generatePrefab(
int seed,
@Nonnull ChunkGenerator chunkGenerator,
@Nullable CaveNode parent,
@Nonnull CaveNode caveNode,
@Nonnull CavePrefabContainer.CavePrefabEntry entry,
@Nonnull Random random
) {
CavePrefabContainer.CavePrefabEntry.CavePrefabConfig config = entry.getConfig();
int iterations = config.getIterations(random.nextDouble());
for (int i = 0; i < iterations; i++) {
int x = caveNode.getBounds().randomX(random);
int z = caveNode.getBounds().randomZ(random);
if (this.isMatchingBiome(seed, chunkGenerator, config.getBiomeMask(), x, z) && config.isMatchingNoiseDensity(seed, x, z)) {
int y = config.getHeight(seed, x, z, caveNode);
if (y != -1
&& config.isMatchingHeight(seed, x, y, z, random)
&& (parent == null || !parent.getShape().shouldReplace(seed, (double)x, (double)z, y))) {
WorldGenPrefabSupplier prefab = entry.getPrefab(random.nextDouble());
PrefabRotation rotation = config.getRotation(random);
CavePrefab entity = new CavePrefab(prefab, rotation, config.getBiomeMask(), config.getBlockMask(), x, y, z);
caveNode.addPrefab(entity);
}
}
}
}
protected boolean isMatchingBiome(int seed, @Nonnull ChunkGenerator chunkGenerator, @Nonnull IIntCondition condition, int x, int z) {
if (condition == ConstantIntCondition.DEFAULT_TRUE) {
return true;
} else if (condition == ConstantIntCondition.DEFAULT_FALSE) {
return false;
} else {
ZoneBiomeResult biomeResult = chunkGenerator.getZoneBiomeResultAt(seed, x, z);
return condition.eval(biomeResult.getBiome().getId());
}
}
protected int getBiomeMaskResult(int seed, @Nonnull ChunkGenerator chunkGenerator, @Nonnull Int2FlagsCondition mask, @Nonnull Vector3d vec) {
if (mask == CaveBiomeMaskFlags.DEFAULT_ALLOW) {
return 7;
} else if (mask == CaveBiomeMaskFlags.DEFAULT_DENY) {
return 0;
} else {
int x = MathUtil.floor(vec.getX());
int z = MathUtil.floor(vec.getZ());
ZoneBiomeResult biomeResult = chunkGenerator.getZoneBiomeResultAt(seed, x, z);
return mask.eval(biomeResult.getBiome().getId());
}
}
}